# How to Create API Routes That Use Server Actions on Edge Runtime in Next.js

> Learn to create Next.js API routes using Server Actions on the Edge Runtime for Cloudflare Workers. Execute Server Actions with Edge bindings like R2, KV, and AI.

- Repository: [Muhammad Arifin/fullstack-next-cloudflare](https://github.com/ifindev/fullstack-next-cloudflare)
- Tags: how-to-guide
- Published: 2026-03-04

---

**You can expose Server Actions through HTTP endpoints by creating a Next.js App Router API route that exports `runtime = 'edge'` and imports your "use server" functions, allowing them to execute on Cloudflare Workers with access to Edge-only bindings like R2, KV, and AI.**

The ifindev/fullstack-next-cloudflare repository demonstrates a production-ready pattern for combining Next.js Server Actions with Cloudflare's Edge runtime. By creating API routes that import and invoke Server Actions while running on the edge, you enable low-latency serverless functions that retain the ergonomic benefits of Next.js actions, including `revalidatePath` and `redirect`.

## Understanding the Edge Runtime Architecture

In this architecture, **Server Actions** contain your server-only business logic in files marked with `"use server"`, while **API routes** provide HTTP endpoints that expose this logic to external clients or non-Next.js frontends. When you export `runtime = 'edge'` from a route file in `src/app/api/…/route.ts`, Next.js compiles the handler as a Cloudflare Worker rather than a Node.js server.

Because the API route and the imported Server Action share the same edge execution environment, the action can safely use Cloudflare-specific globals like `env.AI`, R2 buckets, and KV storage. This pattern is implemented in the `ifindev/fullstack-next-cloudflare` codebase to leverage Cloudflare's distributed edge network while maintaining Next.js developer ergonomics.

## Creating an Edge API Route

To create API routes that use Server Actions on the edge runtime, you configure the runtime export and import your server functions into the route handler.

### Configure the Runtime

Add the runtime export at the top of your route file to enable edge execution:

```tsx
// src/app/api/todos/route.ts
export const runtime = 'edge';

```

This declaration tells Next.js to compile this endpoint as an edge function, making it compatible with Cloudflare Workers and enabling access to edge bindings.

### Implement the Route Handler

Import your Server Action and invoke it within the HTTP handler. The following example from the repository pattern forwards a `multipart/form-data` request to the `createTodoAction` Server Action:

```tsx
// src/app/api/todos/route.ts
export const runtime = 'edge';

import { createTodoAction } from '@/modules/todos/actions/create-todo.action';

export async function POST(request: Request) {
  // Parse a multipart/form-data request (e.g., from a Next.js Form)
  const formData = await request.formData();

  // The Server Action does all validation, DB writes, R2 uploads, etc.
  // It returns a Next.js Response (or throws, which Next will handle)
  return createTodoAction(formData);
}

```

The `createTodoAction` function, defined in [`src/modules/todos/actions/create-todo.action.ts`](https://github.com/ifindev/fullstack-next-cloudflare/blob/main/src/modules/todos/actions/create-todo.action.ts), contains the `"use server"` directive and handles database inserts, R2 file uploads, and cache revalidation. Because both files run on the edge, the action executes in the same Worker context as the route.

## Accessing Cloudflare Edge Bindings

When running on the edge runtime, you can access Cloudflare-specific bindings like AI, R2, and KV directly within your Server Actions or route handlers. The repository uses `getCloudflareContext` from `@opennextjs/cloudflare` to access these bindings.

The following example from [`src/app/api/summarize/route.ts`](https://github.com/ifindev/fullstack-next-cloudflare/blob/main/src/app/api/summarize/route.ts) demonstrates accessing the AI binding within an edge API route:

```tsx
// src/app/api/summarize/route.ts
export const runtime = 'edge';

import { getCloudflareContext } from '@opennextjs/cloudflare';
import { SummarizerService, summarizeRequestSchema } from '@/services/summarizer.service';
import handleApiError from '@/lib/api-error';

export async function POST(request: Request) {
  try {
    const { env } = await getCloudflareContext();          // Edge-only Cloudflare context
    const body = await request.json();
    const { text, config } = summarizeRequestSchema.parse(body);

    // AI is only available on the Edge
    const summarizer = new SummarizerService(env.AI);
    const result = await summarizer.summarize(text, config);

    return new Response(JSON.stringify({ success: true, data: result }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (e) {
    return handleApiError(e);
  }
}

```

This pattern works with any Server Action that requires edge-only bindings—simply import the action into a route configured with `runtime = 'edge'`.

## Full-Stack Implementation Flow

The complete implementation spans three layers: the Server Action containing business logic, the Edge API route exposing it via HTTP, and the client component consuming the endpoint.

### The Server Action

The Server Action in [`src/modules/todos/actions/create-todo.action.ts`](https://github.com/ifindev/fullstack-next-cloudflare/blob/main/src/modules/todos/actions/create-todo.action.ts) handles validation, database operations, and cache management. It uses `"use server"` and can call `revalidatePath` and `redirect` because it runs within the Next.js server context, even when invoked from an edge API route.

### The Edge API Route

As shown previously, the route in [`src/app/api/todos/route.ts`](https://github.com/ifindev/fullstack-next-cloudflare/blob/main/src/app/api/todos/route.ts) exports `runtime = 'edge'` and forwards requests to the Server Action, allowing the action to execute within the Cloudflare Worker environment.

### The Client Component

The client submits data directly to the edge endpoint. The Server Action handles the redirect and revalidation, so the client requires minimal logic:

```tsx
// src/app/dashboard/todos/new-todo.page.tsx
'use client';

export default function NewTodo() {
  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    // Submit the form directly to the Edge API route
    const formData = new FormData(e.currentTarget);
    const res = await fetch('/api/todos', { method: 'POST', body: formData });

    if (res.ok) {
      // Success: redirect handled by the Server Action (revalidatePath + redirect)
      // No extra client-side navigation needed
    } else {
      // handle error...
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* …form fields… */}
      <button type="submit">Create Todo</button>
    </form>
  );
}

```

When the form posts to `/api/todos`, the edge route forwards to `createTodoAction`, which performs validation, persists data, optionally uploads images to R2, revalidates the list page via `revalidatePath`, and issues a `redirect`—all executing at the edge with minimal latency.

## Required Configuration

Two configuration files enable this architecture: the Next.js configuration for local development and the Wrangler configuration for deployment.

### Next.js Configuration

The [`src/next.config.ts`](https://github.com/ifindev/fullstack-next-cloudflare/blob/main/src/next.config.ts) file loads the OpenNext Cloudflare integration, which is required for edge runtime support during local development:

```typescript
// src/next.config.ts
// Loads @opennextjs/cloudflare for local dev; required for Edge runtime support

```

This configuration enables the edge runtime throughout the application, allowing `runtime = 'edge'` exports to function correctly in development.

### Wrangler Configuration

The `wrangler.jsonc` file defines the Cloudflare Worker bindings (R2, AI, KV) that your Server Actions consume when running on the edge:

```jsonc
// wrangler.jsonc
// Cloudflare Workers configuration – defines bindings (R2, AI, KV) 
// that Server Actions can consume when running on the edge

```

Without these bindings declared in `wrangler.jsonc`, the `env` object accessed via `getCloudflareContext` would not contain the necessary resources.

## Summary

- **Export `runtime = 'edge'`** from API routes in `src/app/api/…/route.ts` to compile handlers as Cloudflare Workers
- **Import Server Actions** directly into edge routes—shared runtime allows actions to use Edge-only APIs like R2, KV, and AI
- **Use `getCloudflareContext`** from `@opennextjs/cloudflare` to access bindings within Server Actions or route handlers
- **Configure [`src/next.config.ts`](https://github.com/ifindev/fullstack-next-cloudflare/blob/main/src/next.config.ts)** with OpenNext Cloudflare integration for local edge runtime support
- **Define bindings in `wrangler.jsonc`** to make Cloudflare resources available to your edge functions

## Frequently Asked Questions

### Can I use Server Actions outside of Next.js forms by exposing them as API routes?

Yes. While Server Actions are typically invoked directly from Next.js components, creating an API route with `runtime = 'edge'` that imports and calls the action allows external clients, mobile apps, or third-party services to execute the same logic over standard HTTP.

### Why must I export `runtime = 'edge'` instead of using the Node.js runtime?

The `runtime = 'edge'` export compiles your handler as a Cloudflare Worker, enabling access to Cloudflare-specific bindings like `env.AI`, R2 storage, and KV. Node.js runtime routes cannot access these edge-only resources, and they execute in a different environment than Cloudflare Workers.

### How does `revalidatePath` work when a Server Action is called from an API route?

The `revalidatePath` function works identically whether the Server Action is invoked directly from a component or through an edge API route. Because the action runs within the Next.js edge runtime context, it retains full access to Next.js caching APIs and will revalidate the specified paths accordingly.

### What is the role of `@opennextjs/cloudflare` in this architecture?

The `@opennextjs/cloudflare` package provides the `getCloudflareContext` function and enables the edge runtime compatibility layer for Next.js. According to the ifindev/fullstack-next-cloudflare source code, this integration is essential for accessing Cloudflare bindings and ensuring Server Actions execute correctly on the edge runtime.