[
{
"from": "string", // (required): The path. Supports regexp syntax.
"to": "string", // (required): The destination path.
"status": "number", // (optional): The HTTP Status Code for redirect. Default is empty.
"assets": "boolean", // (optional): Whether to apply the redirect/rewrite to any static file that is not an html file. Default is false.
"hosts": "Array<string>", // (optional): When provided, the redirect rule will apply only when the host name matches.
"data": "object" // (optional): Fetches a JSON document and fills it into the page the rule rewrites to. See Dynamic pages.
}
]
If you omit the status property, or provide a status different than 3xx, Stormkit will not redirect the
request but will simply rewrite the path.
[
{
"from": "/my-path/*",
"to": "/my-new-path/$1"
}
]
In this case, all requests coming to /my-path will be served as if they were coming to /my-new-path.
You can also use redirects as a proxy. If your redirect is an absolute URL (starting with http),
the request will be proxied.
[
{
"from": "/my-path/*",
"to": "https://example.com/my-new-path/$1",
"status": 200
}
]
In this case, all requests coming to /my-path will be proxied to https://example.com/my-new-path/*.
A static site sometimes needs one dynamic route: a page per video, product or profile, with the right <title> and Open Graph tags for crawlers and link previews. Add a data loader to a rewrite rule. Stormkit fetches a JSON document for each request and renders the HTML file the rule rewrites to as a template, with that document as its data. Your markup, styles and asset URLs stay in your build, and your API only returns JSON.
[
{
"from": "/v/*",
"to": "/videos.html",
"data": {
"url": "https://api.example.com/v/$1.json"
}
}
]
A request to /v/abc123 serves /videos.html from your deployment, filled with the document at https://api.example.com/v/abc123.json.
| Property | Required | Description |
|---|---|---|
data.url |
Yes | The JSON document to fetch. Must be https. Wildcard captures from from are available as $1, $2, and so on. |
data.passthroughStatus |
No | When true, an error status from the API becomes the page's status code. Default is false: the page is served with 200. |
Captures are URL-encoded before they are inserted, so a visitor's path can add path segments to data.url but cannot add a query string or fragment. A path whose capture contains a . or .. segment does not match the rule.
A loader only works on a rewrite to a file in your deployment. It is rejected on a proxy rule (a to starting with http) and on a 3xx redirect.
The HTML file is a Go html/template. . is the JSON document, and .field reads a field from it:
<title>{{.title | default "Videos"}} · Example</title>
<meta property="og:title" content="{{.title}}" />
<meta property="og:image" content="{{.thumbnail | default "/og.png"}}" />
<meta name="robots" content="{{.robots | default "noindex"}}" />
{{with .owner}}<span>{{.name}}</span>{{end}}
<ul>{{range .tags}}<li>{{.}}</li>{{end}}</ul>
<script id="__sk_data__" type="application/json">{{.}}</script>
javascript: URL from the API is replaced with #ZgotmplZ.{{.}} inside a <script type="application/json"> block renders the whole document as JSON. Read it from your client code to hydrate the page.default applies when a field is missing, null or an empty string. It does not apply to false or 0: {{.public | default true}} renders false when the API returns false. The built-in or treats false and 0 as empty, so prefer default.{{with .owner}}{{.name}}{{end}} when an object may be missing. {{.owner.name}} fails when owner is absent, and the visitor gets a 500.if, else, range, eq, and, not and the rest of the template actions are available.If the file fails to parse, or fails while rendering, the visitor gets a 500 error page that shows the template error, and the error is written to your runtime logs.
Your page is never blocked on the API for long. The fetch times out after 2 seconds and reads at most 1 MB. When the API fails, the document is empty and status holds the API's status code, or 0 when the API could not be reached. Use them to show something else for a missing or withheld record:
{{if .}}
<h1>{{.title}}</h1>
<p>By {{.owner.name}}</p>
{{else if eq status 410}}
<h1>This video is no longer available</h1>
{{else if eq status 404}}
<h1>Video not found</h1>
{{else}}
<h1>Something went wrong. Please try again later.</h1>
{{end}}
{{if .}} is false when the document is empty, so the fields inside it, including nested ones like .owner.name, are only read when the API returned data.
status set to 0.404): the page is rendered with an empty document, and the error response body is ignored. status holds the error status. With "passthroughStatus": true the visitor gets that status code too, so a deleted record returns a real 404.{{ in the file is read as template syntax, and text that is not valid template syntax is a template error. To output a literal {{, write {{"{{"}}.Stormkit does not cache pages with a loader or their JSON documents: every request calls your API. Stormkit also does not send ETag or Last-Modified for these pages, so browsers and CDNs always get the current data. If an endpoint is expensive, cache it in your API.
The request to your API carries the visitor's details, so it can count views and tell people apart from bots and link unfurlers:
| Header | Value |
|---|---|
User-Agent |
The visitor's User-Agent |
X-Forwarded-For |
The visitor's IP address |
X-Real-IP |
The visitor's IP address |
Accept |
application/json |
Identical requests from the same visitor that arrive at the same time share a single call to your API. Requests from different visitors are never combined.
Stormkit applies the first rule that matches, and * also matches /. List more specific rules first: here /v/abc/embed would match /v/* if that rule came first.
[
{
"from": "/v/*/embed",
"to": "/embed.html",
"data": { "url": "https://api.example.com/v/$1.json" }
},
{
"from": "/v/*",
"to": "/videos.html",
"data": { "url": "https://api.example.com/v/$1.json" }
}
]
The file your rule rewrites to is a normal file in your deployment, so /videos.html can also be opened directly, showing its raw template. Redirect it away. List this rule after the loader rule:
[
{
"from": "/v/*",
"to": "/videos.html",
"data": { "url": "https://api.example.com/v/$1.json" }
},
{
"from": "/videos(.html)?",
"to": "/",
"status": 301
}
]
Stormkit applies the first rule that matches, so /v/abc123 still rewrites to the template while direct requests to /videos and /videos.html are redirected.
A loader only connects to public addresses. On a self-hosted instance whose API runs on a private network, set STORMKIT_PAGE_DATA_INSECURE=true to allow private addresses and plain http URLs. See Advanced Configuration.
[
{
"from": "stormkit.io",
"to": "www.stormkit.io",
"assets": true,
"status": 301
}
]
[
{
"from": "/*",
"to": "/index.html"
}
]
The above example will rewrite all requests to index.html. By setting assets false This is useful for single page applications.
[
{
"from": "/documentation/*/page/*",
"to": "/docs/$1/$2"
},
{
"from": "/documentation$",
"to": "/docs"
}
]
You can use regexp syntax for redirects. The example above creates two redirects.
/documentation/welcome/page/getting-started to /docs/welcome/getting-started./documentation to /docs.Note the $amp; sign at the end of the string. That sign simply tells to redirect only the path /documentation and not anything that contains /documentation.
[
{
"from": "/path",
"to": "/new-path",
"hosts": ["example-a.org"]
},
{
"from": "/path",
"to": "/different-path",
"hosts": ["example-b.org", "example-c.org"]
}
]
If you have multiple domains configured for your environment, you can specify for which host name the redirect rule should apply to.
The example above will rewrite the /path to /new-path for example-a.org and to /different-path for example-b.org and example-c.org.
Please note that if your application contains API routes, paths starting with /api will not be matched.
This is to allow /api routes to handle the redirect themselves.
If you do not have any API function, this rule does not apply.
You can configure the API routes through the Serverless configuration section.
By Default, when a page is not found, Stormkit will try to serve /404.html or /error.html if any of these files are found in your deployment. You can customize this behaviour as follows:
Custom Error File fieldThis setting will be applied to all of your deployments and take effect instantly. There is no need for a deployment.
Note If you have API routes configured, the custom error file will not be applied to the paths starting
with your API Path - which is /api by default.
Note Similarly, if you have serverless side logic, the custom error file will not be applied.
You can specify the same rules at an environment level. To do so:
These rules will be applied to all of your deployments and take effect instantly. There is no need for a deployment.