Upgrading from Edgio Applications version 6 or earlier may require significant changes to your CDN-as-code configuration as certain core legacy components have limited support. View our upgrading guide.
Our CDN-as-code approach to configuration allows you to configure CDN behavior using EdgeJS within a file (
routes.[js|ts]
) stored alongside your code. This allows you to leverage the power of source control for collaboration and to link your CDN configurations with specific versions of your web application.Quick Start
Get started with CDN-as-code by either experimenting with:
-
Our sample websites:
-
Your web application or website.
Perform the following steps to use Edgio to improve the performance of your web application or website:
-
Create a property. If you have already performed this step, proceed to the next step.
-
Use the Edgio CLI to initialize your property. If you have already performed this step, proceed to the next step.This step requires Node.js v16.x.Install the Edgio CLI, initialize your property, and then deploy it by running the following command from the root directory of your web application or website:Bash1npx @edgio/cli@latest init \2 --edgioVersion latest \3 --name <PROPERTY> \4 --deployReplace
<PROPERTY>
with the name of the property defined in step 1. You should only use lower-case characters and replace spaces with dashes (e.g.,my-property
). -
Define routes that determine how Edgio will handle that traffic.
-
Deploy your property to the Edgio network.
Routes File
The
routes.[js|ts]
file defines a set of routes. A route:- Identifies a set of requests by HTTP method, URL path, query string parameters, cookies, and request headers.
- Determines how our CDN will handle the above requests. For example, you may configure those requests to be cached, prefetched, passed through without modification, or served as static content.
By default, our CLI automatically creates
routes.js
and edgio.config.js
upon initializing a property (edgio init
). If your web application supports TypeScript and it uses a framework for which we have a TypeScript implementation, then our CLI will create routes.ts
instead of routes.js
.Default Route Configuration
By default, your
routes.[js|ts]
contains the following configuration:JavaScript./routes.js
1// This file was added by edgio init.2// You should commit this file to source control.3import {Router, edgioRoutes} from '@edgio/core';45export default new Router()6 // Here is an example where we cache api/* at the edge but prevent caching in the browser7 // .match('/api/:path*', {8 // caching: {9 // max_age: '1d',10 // stale_while_revalidate: '1h',11 // bypass_client_cache: true,12 // service_worker_max_age: '1d',13 // },14 // })1516 // plugin enabling basic Edgio functionality17 .use(edgioRoutes);
The above configuration shows an example of how you can match all requests to the
/api/
URL path and cache them at the edge for 1 day.Routes
A route identifies a set of requests through any combination of URL path, HTTP method, cookies, request headers, and query string parameters. The following routes show various ways for identifying requests.
-
Match all requests:JavaScript1router.match('/:path*', {2 // route handler goes here3});
-
Match all
GET
requests whose URL path starts with/marketing/images/
:JavaScript1router.get('/marketing/images/:path*', {2 // route handler goes here3}); -
Match all
GET
andPOST
requests whose URL path starts with/marketing/images/
and contain thesport
request header set tobasketball
:JavaScript1router.match(2 {3 path: '/marketing/images/:path*',4 method: /GET|POST/i, // regular expression5 headers: {sport: /^basketball$/i}, // keys are header names; values are regular expressions6 },7 {8 // route features goes here9 }10);
Once you have identified a set of requests, you need to define how Edgio will handle those requests. The following routes show various ways in which requests can be processed.
- Apply a caching policy to all requests and proxy cache misses to the
origin
backend:JavaScript1router.match('/:path*', {2 {3 caching: {4 max_age: "1h"5 },6 origin: {7 set_origin: "origin"8 }9 }10}) - Set the
images
response header and proxy cache misses to theorigin
backend for allGET
requests whose URL path starts with/marketing/images/
:JavaScript1router.get('/marketing/images/:path*', {2 headers: {3 set_response_headers: {4 images: 'true',5 },6 },7 origin: {8 set_origin: 'origin',9 },10});
Defining Routes
Routes are defined by calling a function on the
Router
object based on the HTTP method you intend to match. For example, you can handle a GET
request a specific path or pattern using the Router.get(...)
function. The router contains methods for all the supported HTTP methods. The following methods are available:delete
get
head
match
(matches any HTTP method)options
patch
post
put
A full list of supported functions can be found in the Router API documentation.
Route Method Signature
Using
.match()
as an example, the method signature is as follows:TypeScript
1match(2 criteria: RouteCriteria | string | string[] | RegExp,3 features: FeaturesParam4)
The first argument
criteria
defines how to match a request. It can be a string (or array of strings), a regular expression, or an object of type RouteCriteria
. For example, to match requests to the /api/*
URL path, you could define the criteria as follows:JavaScript
1// match by named parameter2router.match('/api/:path*', {3 // route features goes here4});56// match by regular expression7router.match(/^\/api\/(.*)$/, {8 // route features goes here9});1011// match by `path` property12router.match(13 {14 path: '/api/:path*',15 },16 {17 // route features goes here18 }19);
All of the above examples are equivalent and show the various ways in which you can define the route criteria.
The second argument
features
, also referred to as the route handler, defines how to handle a request such as how to cache the response, how to proxy the request to the origin, or how to modify the request and response headers. This is an object of type Features
and the full list of supported features can be found in the Features API reference.We will now define a route by uncommenting the
match()
method in your routes.[js|ts]
file. It should now look similar to the following configuration:JavaScript./routes.js
1export default new Router()2 // Here is an example where we cache api/* at the edge but prevent caching in the browser3 .match('/api/:path*', {4 caching: {5 max_age: '1d',6 stale_while_revalidate: '1h',7 bypass_client_cache: true,8 service_worker_max_age: '1d',9 },10 })1112 // plugin enabling basic Edgio functionality13 .use(edgioRoutes);
The above route matches all requests that start with
/api/
and instructs Edgio to:- Cache those requests on our network for one day.
- Allow us to serve stale content for one hour.
- Instruct the browser to treat the response as immediately stale.
- Allow prefetched requests to be served from cache for one day.
- Proxy those requests to your
origin
backend when we cannot serve them from cache.
We will now add a route that applies the same caching policy to all JavaScript (i.e.,
.js
and .mjs
) and CSS files.JavaScript./routes.js
1// Cache stylesheets and scripts, but prevent browser caching2router.match('/:path*/:file.:ext(js|mjs|css)', {3 caching: {4 max_age: '1d',5 stale_while_revalidate: '1h',6 service_worker_max_age: '1d',7 bypass_client_cache: true,8 },9 headers: {10 set_response_headers: {11 'cache-control': 'public, max-age=86400',12 },13 remove_origin_response_headers: ['set-cookie'],14 },15 origin: {16 set_origin: 'origin',17 },18});
The above route instructs Edgio to perform the following actions for all requests whose file extension matches
js
, mjs
, or css
:- Set the
cache-control
response header to:cache-control: public, max-age=86400
- Remove the
set-cookie
response header. Edgio will not cache a response when theset-cookie
response header is present. - Apply the caching policy.
- Proxy these requests to your
origin
backend when we cannot serve them from cache.
Your
routes.[js|ts]
should now look similar to the following:JavaScript./routes.js
1import {Router} from '@edgio/core/router';23export default new Router()4 .match('/api/:path*', {5 caching: {6 max_age: '1d',7 stale_while_revalidate: '1h',8 service_worker_max_age: '1d',9 bypass_client_cache: true,10 },11 origin: {12 set_origin: 'origin',13 },14 })1516 // Cache stylesheets and scripts, but prevent browser caching17 .match('/:path*/:file.:ext(js|mjs|css)', {18 caching: {19 max_age: '1d',20 stale_while_revalidate: '1h',21 service_worker_max_age: '1d',22 bypass_client_cache: true,23 },24 headers: {25 set_response_headers: {26 'cache-control': 'public, max-age=86400',27 },28 remove_origin_response_headers: ['set-cookie'],29 },30 origin: {31 set_origin: 'origin',32 },33 })3435 // plugin enabling basic Edgio functionality36 .use(edgioRoutes);
Conditional Routes
Conditional routes allow you to apply rules to a request using advanced if/then logic by the means of logical and comparison operators.
Using the .conditional()
method
Using the previous example above for caching the
/api/*
path, we can rewrite the same route using the conditional()
method. This method accepts a single argument of type Matches
. You can see the full specification of the Matches
type in the API reference.JavaScript./routes.js
1import {Router} from '@edgio/core/router';23export default new Router().conditional({4 if: [5 {6 and: [7 {8 '===': [9 {10 request: 'method',11 },12 'GET',13 ],14 },15 {16 '==': [17 {18 request: 'path',19 },20 '/api/:path*',21 ],22 },23 ],24 },25 {26 caching: {27 max_age: '1d',28 stale_while_revalidate: '1h',29 service_worker_max_age: '1d',30 bypass_client_cache: true,31 },32 origin: {33 set_origin: 'origin',34 },35 },36 ],37});
This is equivalent to the previous example. Broken down by line:
- The
if
array contains two objects. The first object defines an array of conditions that must be met using theand
logic operator. The second object defines the features to apply if all conditions are met.- The
and
array requires all the following conditions to be satisfied:- the HTTP request method strictly equals (
===
)GET
- the request path is a simple match (
==
)/api/:path*
. (eg./api/foo
or/api/foo/bar
)
- the HTTP request method strictly equals (
- Assuming all conditions are met, the following features will be applied:
- the request will be cached at the edge for one day.
- the request will be forwarded to the origin when the cache is stale, and then cached for one day.
- The
Types of Operators and Conditionals
Operators
The
Boolean
type is used as a logical operator in the if
array. You may specify an and
or or
operator. The and
operator requires all conditions to be met. The or
operator requires only one condition to be met.Currently, only a single
and/or
operator is supported. The following would be an invalid use of multiple operators:JavaScript
1{2 if: [3 {4 and: [5 {6 // conition7 },8 {9 // condition10 },11 ],12 or: [13 {14 // condition15 },16 ],17 },18 {19 // features20 },21 ],22}
Conditionals
Conditionals define the expectations that must be met, using comparison operators, for the features to be applied to the request. This example of a single conditional identifies the type of comparison to take against the
RulesVariables
and the expected value:JavaScript
1{2 '===': [ // comparison operator3 {4 request: 'method', // rules variable5 },6 'GET', // expected value7 ],8}
Comparison Operators
Operator | Description |
---|---|
== | Simple match. |
!= | Negated simple match. |
=== | Strict match. |
!== | Negated strict match. |
< | Less than. |
<= | Less than or equal to. |
> | Greater than. |
>= | Greater than or equal to. |
in | Value is in the array. |
not_in | Value is not in the array. |
=~ | Regular expression match. |
!~ | Negated regular expression match. |
Example
This example shows multiple conditionals that use various comparison operators and rules variables:
JavaScript./routes.js
1import {Router} from '@edgio/core/router';23export default new Router().conditional({4 if: [5 {6 and: [7 {8 '=~': [9 {10 'request.header': 'x-test',11 },12 '^foo$',13 ],14 },15 {16 and: [17 {18 '!==': [19 {20 request: 'method',21 },22 'DELETE',23 ],24 },25 {26 and: [27 {28 '==': [29 {30 request: 'path',31 },32 '/api/v:version/:path*',33 ],34 },35 {36 and: [37 {38 not_in: [39 {40 request: 'path',41 },42 ['/api/v1', '/api/v2'],43 ],44 },45 {46 and: [47 {48 '!~': [49 {50 'request.cookie': 'user_level',51 },52 '^level_(1|2)$',53 ],54 },55 {56 and: [57 {58 '===': [59 {60 device: 'is_robot',61 },62 true,63 ],64 },65 {66 '>=': [67 {68 device: 'resolution_height',69 },70 800,71 ],72 },73 ],74 },75 ],76 },77 ],78 },79 ],80 },81 ],82 },83 ],84 },85 {86 caching: {87 bypass_client_cache: true,88 service_worker_max_age: '1d',89 max_age: {90 200: '1d',91 },92 stale_while_revalidate: '1h',93 },94 origin: {95 set_origin: 'origin',96 },97 },98 ],99});
Testing Locally
You may run Edgio in local development mode to preview your website on your local machine prior to deployment. Local development mode allows for rapid development by allowing you to quickly test changes prior to deployment.
- From the command line or terminal, type
edgio dev
. - Preview your website by loading
https://127.0.0.1:3000
from within your preferred web browser.
Deploying Your Property
Evaluate site performance and QA functionality by deploying your property to Edgio. Run the following command from your property’s root directory:
Bash
1edgio deploy
Assess performance and caching behavior from the Edgio Console. Fine-tune your configuration by adding routes and then redeploying your property. Once you are ready to serve production traffic through Edgio, update your site’s DNS to point to our service.
Examples
Use our sample website to gain hands-on experience on how to set up Edgio Performance. Specifically, you can browse our sample websites, view their source code, and even experiment on them by deploying them to Edgio.
Simple Example
This example demonstrates a basic Edgio configuration for
publicdomainreview.org
. It contains two routes that cache content according to their file extension.Issues?
If you have any issues during this process, check our forums for assistance.