Building Output Configuration
The build output configuration is a file system-based standard for defining framework artifacts. It provides a standardized method to enable framework adapters to unify build results in a format output and deploy to the EdgeOne Pages platform.
Overview
The build output API closely corresponds to EdgeOne Pages product features in a clear and easy-to-understand way. If you are a framework author hoping for seamless integration with EdgeOne Pages, you can use this reference to learn which files the framework should output to the
.edgeone directory.You can create your own
.edgeone directory and fill it according to this standard. In the following text, we will provide detailed instructions so that developers can understand how to use the build output for their own framework adapter.Directory Structure in Its Entirety
Developers need to focus on the core in
.edgeone/cloud-functions/ssr-node/config.json. The config.json file contains deployment configuration messages.For Web full-stack framework services, the entry file should be named
handler.js.Supported Fields in config.json
version
version attribute indicates the implemented Build Output API version. The document description version is 3.{"version": 3}
routes
routes attribute describes routing rules applied to deployment. Routing can be used to point specific URL paths to other paths under deployment, attach response headers to paths, implement redirection and various routing related use cases.type Route = Source | Handler;
Source route
type Source = {src: string;dest?: string;headers?: Record<string, string>;methods?: string[];continue?: boolean;status?: number;has?: HasField[];missing?: HasField[];};
Field | Type | Required | Description |
src | String | Yes | A regular expression compatible with RE2, used to match each passed in path name (excluding query string). |
dest | String | No | Rewrite the target path or complete URL (including querystring), supporting capture groups $1, $2. If not provided, directly use the original path from the client request. |
headers | Record <string, string> | No | A group of HTTP response headers that apply to the response. |
methods | String[] | No | A group of HTTP method types. If not provided, any HTTP method request will become a candidate for the route. |
continue | Boolean | No | A boolean value used to change matching behavior. If it is true, the route will continue matching follow-up rules even if src matches. |
status | Number | No | The status code of the response. It must be used in conjunction with headers.Location to implement redirection. Location supports capture groups $1, $2, etc. |
has | HasField[] | No | HTTP request conditions (header/cookie/query/host) that must be met for application routing. |
missing | HasField[] | No | HTTP request conditions (reverse condition matching) that must fail to satisfy for application routing. |
Source route: HasField
type HasField = Array<{ type: 'host', value: string }{type: 'header' | 'cookie' | 'query';key: string;value?: string;}>;
Field | Type | Required | Description |
type | "host" | "header" | "cookie" | "query" | Yes | Confirm the HasField Type. |
key | String | No | header, cookie, and query are required. The matching key name. |
value | String | No | Value to match (support regular expressions). |
Handler route
The routing system uses the
handle value to identify the routing stage boundary. EdgeOne only supports handle: "filesystem".type Handler = {handle: 'filesystem';};
Field | Type | Required | Description |
handle | "filesystem" | Yes | The boundary tag for static file search. Only supports "filesystem". |
{"version": 3,"routes": [// Stage 1: Preprocessing stage (before filesystem)// Use: redirect, set response header{ "src": "^/_next/static/(.*)$", "headers": { "cache-control": "public, max-age=31536000, immutable" } },{ "handle": "filesystem" },// Phase 2: Back-to-origin stage (after filesystem)// For: API routing, SSR webpage, function call{ "src": "^/api/(.*)$", "dest": "/api/$1" },{ "src": "/.*" }]}
Note:
handle: "filesystem" The routing configuration format before and after is identical, no special processing required.Output Location
Based on the Builder type, write corresponding files to different directories. The full-stack Web framework is placed in
cloud-functions/ssr-node.Builder Type | Output Location |
static resource | assets/ |
Node.js SSR functions | cloud-functions/ssr-node/ |
Node.js API functions | cloud-functions/api-node/ |
Go API functions | cloud-functions/api-go/ |
Python API functions | cloud-functions/api-python/ |
Edge functions | edge-functions/ |
Node.js API
Source code directory structure:
cloud-functions/├── api/│ ├── users.js│ └── posts/[id].js└── hello.js
Build output directory structure:
cloud-functions/├── api-node/│ ├── node_modules/│ ├── index.mjs│ └── config.json...
generated
config.json:{"version": 3,"routes": [{ "src": "^/api/users$", "dest": "/api/users" },{ "src": "^/api/posts/([^/]+)$", "dest": "/api/posts/$1" },{"src": "^/hello-node$","methods": ["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"]}]}
Go API
Handler Mode
Source code directory structure:
cloud-functions/├── api/│ ├── users.go│ └── posts/[id].go├── health.go├── go.mod└── go.sum
Build output directory structure:
cloud-functions/api-go├── config.json├── go.mod└── main.go // output product entry file name fixed as main in handler mode
generated
config.json:{"version": 3,"routes": [{"src": "^/api/users/?$"},{"src": "^/health/?$"},{"src": "^/api/posts/([^/]+)/?$"}]}
Framework Mode
Source code directory structure:
cloud-functions/├── api.go├── go.mod└── go.sum
Build output directory structure:
cloud-functions/api-go├── config.json├── go.mod└── api.go //This file has the same name as the entry file
generated
config.json:{"version": 3,"framework": "gin","routes": [{"src": "^/api(.*)$"}]}
Python API
Handler Mode
Source code directory structure:
cloud-functions/├── api/│ └── users.py├── hello.py└── requirements.txt (optional)
Build output directory structure:
cloud-functions/api-python├── config.json├── app.py // Entry file, fixed as app.py├── requirements.txt├── api/│ └── users.py├── hello.py└── <dependencies>/ // Third-party dependency package (installed under the product directory)
generated
config.json:{"vsersion": 3,"routes": [{"src": "^/api/users$"},{"src": "^/hello$"}]}
Framework Mode
Source code directory structure (using FastAPI as an example):
cloud-functions/├── demo-fastapi.py└── requirements.txt (optional)
Build output directory structure:
cloud-functions/api-python├── config.json├── app.py // Entry file, fixed as app.py├── requirements.txt├── demo-fastapi.py└── <dependencies>/ // Third-party dependency package (such as fastapi, uvicorn)
generated
config.json:{"version": 3,"routes": [{"src": "^/demo-fastapi$"}]}
Common Scenes
URL Redirect
// Fixed path redirection{ "src": "^/old-path$", "headers": { "Location": "/new-path" }, "status": 301 }// Real-time path redirection (support capture group){ "src": "^/blog/(.*)$", "headers": { "Location": "/posts/$1" }, "status": 301 }// Full URL redirect{ "src": "^/external$", "headers": { "Location": "https://example.com/page" }, "status": 302 }
Note:
Redirect using
headers.Location + status compositeLocation can be a relative path (such as /new-path) or a complete URLLocation can use capture group variables like $1, $2 to implement dynamic redirection.Catch-all
Rewrite all requests to the root path index.html, usually used for single-page applications (SPA).
{"src": "/.*","dest": "index.html"}
Set Response Header
{"src": "^/_next/static/(.*)$","headers": { "cache-control": "public, max-age=31536000, immutable" }}
Clean URLs
{ "src": "^/about$", "dest": "/about.html" }
Dynamic Routing
{ "src": "^/blog/([^/]+)$", "dest": "/blog/$1" }
Note: Use regular expression capture group $1 to transmit dynamic parameter.
Complete Example
{"version": 3,"routes": [{"src": "^/([^.]+[^/.])$","dest": "/$1/","continue": true},{"src": "/test-ssg","headers": {"Cache-Control": "max-age=3600"}},{"src": "/api/cookies-test","headers": {"Cache-Control": "public, max-age=60, stale-while-revalidate=300"}},{"handle": "filesystem"},{"src": "^/about$","dest": "/about.html"},{"src": "^/blog/([^/]+)$","dest": "/blog/$1"},{"src": "^/api/cookies-test-cache$"},{"src": "^/api/seconde/query-test$"},{"src": "^/api/cookies-test$"},{"src": "^/posts/([^/]+)$"},{"src": "^/auth$"},{"src": "^/$"},{"src": "^/(.*)$"}]}
Current Limitation
The Web full-stack framework API routing is uniformly specified to execute in Node Server and unable to execute in Edge Server. If needed, you can use Edge Functions in the framework.
