Silgi
Plugins

CORS

Add cross-origin resource sharing headers to your API responses.

When your API runs on one domain (like api.example.com) and your frontend on another (like app.example.com), browsers block the requests by default. CORS headers tell the browser it's safe to proceed.

Silgi provides corsHeaders() — a function that returns the right headers for your configuration.

Basic usage

import {  } from 'silgi/cors'

const  = ({
  : 'https://app.example.com',
  : true,
})

This returns a plain object:

{
  "access-control-allow-origin": "https://app.example.com",
  "access-control-allow-credentials": "true",
  "access-control-allow-methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
  "access-control-allow-headers": "Content-Type, Authorization"
}

You can merge these headers into your responses however your server setup requires.

Allow all origins

The default (no origin option or origin: "*") allows any origin:

import {  } from 'silgi/cors'

const  = ()
// "access-control-allow-origin": "*"

Using origin: "*" with credentials: true doesn't work — browsers reject it. If you need credentials, specify the exact origin.

Multiple origins

Pass an array to allow several specific origins:

import {  } from 'silgi/cors'

const  = (
  {
    : ['https://app.example.com', 'https://admin.example.com'],
  },
  requestOrigin,
)

The second argument is the requesting origin (from the Origin header on the incoming request). Silgi checks if it's in the list and responds with the matching origin. A Vary: Origin header is automatically included so caches work correctly.

Dynamic origin matching

For more complex rules, pass a function:

import {  } from 'silgi/cors'

const  = (
  {
    : () => {
      return .('.example.com')
    },
  },
  req.headers.get('origin'),
)

The function receives the requesting origin and returns true to allow it or false to block it. Like array origins, Vary: Origin is added automatically.

All options

OptionTypeDefaultDescription
originstring | string[] | (origin) => boolean"*"Which origins are allowed
methodsstring[]["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]Allowed HTTP methods
allowedHeadersstring[]["Content-Type", "Authorization"]Headers the client can send
exposedHeadersstring[]noneResponse headers the client can read
credentialsbooleanfalseAllow cookies and auth headers
maxAgenumbernonePreflight cache duration in seconds

Example with handler()

If you're using handler() with a custom server, you can wrap it to add CORS headers:

import {  } from 'silgi/cors'

const  = s.handler(appRouter)
const  = ({ : 'https://app.example.com', : true })

async function (: Request): <Response> {
  // Handle preflight
  if (. === 'OPTIONS') {
    return new (null, { : 204, :  })
  }

  const  = await ()

  // Add CORS headers to the response
  const  = new (.headers)
  for (const [, ] of .()) {
    .(, )
  }
  return new (.body, {
    : .status,
    ,
  })
}

What's next?

  • Serverserve() and handler() options
  • Plugins — other available plugins
  • Client — setting up the client that sends cross-origin requests

On this page