Sign Up for Free

RunKit +

Try any Node.js package right in your browser

This is a playground to test code. It runs a full Node.js environment and already has all of npm’s 400,000 packages pre-installed, including @fab/static with all npm packages installed. Try it out:

var _static = require("@fab/static")

This service is provided by RunKit and is not affiliated with npm, Inc or the package authors.

@fab/static v0.1.8

Compile static-site projects into FABs

name: "@fab/static" route: "/packages/fab-static" menu: Packages

💎 @fab/static

Builds a FAB from a directory of static HTML and assets, with an optional server-side component.

oclif  Version  Downloads/week  License 

Getting Started

Install @fab/static as a development dependency:

yarn add --dev @fab/static
npm install --dev @fab/static

Add a couple of scripts to your package.json:

  "scripts": {
    "build": "[your existing build step]",
+   "build:fab": "npm run build && npm run fab:compile",
+   "fab:compile": "fab-static [dirname]"

Replace dirname with wherever your built files live (build for Create React App & friends, public for Gatsby, dist for some others)

We've added two scripts here, fab:compile which runs the fab-static builder, and build:fab that builds the project first. Most of the time, and especially you're using a FAB-enabled platform like, you'll mostly run build:fab, but having a separate fab:compile step can be handy as you set things up.

You can test it out by running:

npm run build:fab

Once this is complete, you should have a file (and a .fab directory with a bunch of build files). Those don't need to be checked in to your repository, so you can add them to your .gitignore file with this one-liner:

echo "\n.fab\" >> .gitignore

If you want to spin up your file locally, you can use @fab/serve. You can either install it globally:

yarn global add @fab/serve
npm install --global @fab/serve


Or use the awesome npx (which is bundled with NodeJS) to run a command-line NPM package without needing to install it:

npx @fab/serve

You should see your app running on http://localhost:3000!

Note: this process will add one file and one directory .fab into your project.


@fab/static takes the following options:

  $ fab-static [DIRECTORY]

  -h, --help                         show CLI help
  -o, --output=output                Output FAB file (default
  -p, --prod-settings=prod-settings  Path to production settings json
  -s, --server=server                Path to server entry file or directory
  -w, --working-dir=working-dir      Intermediate directory for working (default .fab)

  $ fab-static ~/src/my-project/build

Efficiently handling assets

The file only allows two components—the first is a server.js, which is auto-generated by @fab/static, and the second is an _assets directory. If your assets aren't in an _assets subdirectory (e.g. a public or static directory instead), @fab/static will automatically move them and generate server-side code to wire things up at runtime. This process works fine, but it's inefficient.

To read more about the rewriting process, visit the @fab/compile documentation, or for a more general overview of why _assets is a core part of the FAB spec, visit

Environment Variables

The FAB format has first-class support for environment variables which you can read about here:

To specify production environment variables to be bundled into the FAB itself, add a production-settings.json file in the same directory as your package.json file and it will be automatically included into the build. You can also specify a path with -p or --prod-settings if you'd prefer to keep your settings file elsewhere/name it differently.

A production settings file might look like:

  "API_URL": "",
  "CLIENT_ID": "1cd5e6a4871f98616a38abb2eada56868ca5aad2"

These values are for the production environment (read why). To supply non-production variables that will be injected in place of these settings, consult the documentation of your hosting platform e.g. Linc

Accessing Environment Variables at Runtime

@fab/static dynamically injects a <script> tag into any HTML response as it's being streamed to the client:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8" />
    <!-- ... -->
    <!-- ... -->

That <script> tag has the following format:

<script type="text/javascript">
  window.FAB_SETTINGS = {
    "API_URL": ""

Whatever the settings object passed to render (which will be a combination of production settings as well as any environment-specific overrides), @fab/static will serialise them to JSON and inject them as window.FAB_SETTINGS. This code will execute before any other, meaning you can always rely on FAB_SETTINGS to be available by the time your app is booted.

  // ...

To use the same environment variables during development, it's recommended to add a layer of abstraction between FAB_SETTINGS (available once the FAB is built) and process.env (available during development). For example

// src/config.js

const lookupEnvVar = name => {
  // Use FAB_SETTINGS if defined
  if (typeof FAB_SETTINGS === 'object') {
    return FAB_SETTINGS[name]
  // Otherwise use process.env
  } else {
    // Note: some build systems (like Create React App) only expose
    // process.env vars that start with a prefix (like REACT_APP_)
    return process.env[`REACT_APP_${name}`]

export default {
  API_URL: lookupEnvVar('API_URL'),
  API_KEY: lookupEnvVar('API_KEY'),
  // ...

You can use the config throughout your app like so:

import config from '../config'

  // ...

Adding a server

Despite the name, @fab/static is capable of running virtually any server-side logic you'd like. From use-cases like rewriting or forwarding URLs, proxying APIs, or simply providing a health check, you can supercharge your FAB by using the -s or --server flag to fab-static.

For simple use-cases, you can use a single file:

fab-static --server path/to/server.js

For more complex setups, you can specify a whole directory which will be bundled into the FAB:

fab-static --server path/to/server

In this example, the path/to/server/index.js will be used as the entry point, but the whole directory will be copied into the FAB.

Server API

Your server.js or server/index.js file can export one of three endpoints:

export async function modifyRequest(settings, request) {
  // default behaviour is nothing, needs no return value

export async function route(settings, path, request) {
  // must return something, by default returns the path unchanged
  return path

export async function modifyResponse(settings, response) {
  // default behaviour is nothing, needs no return value
RunKit is a free, in-browser JavaScript dev environment for prototyping Node.js code, with every npm package installed. Sign up to share your code.
Sign Up for Free