Express Svelte

A straightforward Svelte view engine for Express.


Install via npm.

npm install express-svelte --save

Goals & Design

I created this project because of the lack of a simple way to create, compile, render and hydrate views for simple non-SPA web apps.

It is a view engine rather than an app framework (like svelte-kit, Sapper or Next.js).

It bypasses the express built-in view engine and instead it sets a res.svelte function. The reason behind this is to avoid be tightly coupled with express (can be easily extended for use with Polka) and some limitations like the app.locals and res.locals merge logic.


  • Static content without hydration.
  • Hydration.
  • Compile views asynchronously (no need of svelte/register) with sane defaults and customizable configuration.
    • Support for preprocess plugins.
    • Replace values (like process.env.NODE_ENV and process.browser).
    • Dedupe dependencies.
    • Sourcemap support.
    • Cache.
  • Global values set at top-level component via Svelte Context API:
    • Global props based on opts.globalProps.
    • Global stores based on opts.globalStores.
  • Customizable root lodash template (very fast and similar to EJS syntax).

Basic setup and usage

Full setup example available at express-svelte-example.

const expressSvelte = require('express-svelte');
// ...

// Configure
app.use(expressSvelte({ /* config */ }));

// Render view
app.get((req, res, next) => {
    res.svelte('View', {
        props: { /* ... */ },
        globalProps: { /* ... */ },
        globalStores: { /* ... */ }

Config options


Type: String | String[].

Defaults to process.cwd() + "/views".

A directory or an array of directories for the app's views (svelte files).


Type: String | String[].

Defaults to process.cwd() + "/public/dist".

A directory or an array of directories for the app's views compiled bundles (js and css files) generated by the client rollup config.


Type: String.

Defaults to "[name]-[hash][extname]".

Bundles rollup output format. [name] will be used for easy reference at globalAssets.


Type: String.

Defaults to "".

An optional host to prefix JS or CSS bundles. Eg, a CDN host or different subdomain.


Type: String.

Defaults to ".svelte"".

Engine default extension resolution. The lookup has the same behavior as Express built-in res.render function. If you do res.svelte('View') it will look for "View.svelte".


Type: String.

Defaults to absolute path to package's default root lodash template.

If the default template does not fit for you, you can set a customized root template.


Type: Boolean.

Defaults to process.env.NODE_ENV or "development" if not set.

Used to determine dev and cache values if not specified.

It replaces process.env.NODE_ENV with @rollup/plugin-replace plugin by default.


Type: Boolean.

Default is inferred with env. If env is "development" or "testing" is set to true.

It sets dev, preserveComments and preserveWhitespace properties at rollup-plugin-svelte plugin and enables source map support.


Type: Boolean.

Default is inferred with env. If env is "development" or "testing" is set to false.


Type: Boolean.

Default is false.

Hydratable value to be used at rollup-plugin-svelte plugin.

If disabled, props and globals won't be exposed in the HTML.


Type: Boolean.

Default is true.

A combination of modern and legacy builds will be used, the modern with type="module" attribute and the legacy with the nomodule attribute.

Browsers that understand type="module" should ignore scripts with a nomodule attribute. This means you can serve a module tree to module-supporting browsers while providing a fall-back to other browsers.

You can read the full article about this here.

If enabled, when using rollup-plugin-express-svelte it needs to be configured to build both bundles. You can check out the express-svelte-example.


Type: Object.

Default is {}.

Object with key-value pairs to be replaced with @rollup/plugin-replace plugin plugin.

Like process.env.NODE_ENV replacement, a default replacement for process.env.browser is made.


Type: Array.

Default is [].

Preprocess array to be used at rollup-plugin-svelte plugin.


Type: String[].

Default is [].

Dependencies array to dedupe array to be used at @rollup/plugin-node-resolve plugin.

Every dependency you add will extend the following dedupe array:


Render options


Type: Boolean.

Overrides option set at the main config.


Type: Boolean.

Overrides option set at the main config.


Type: String.

Overrides option set at the main config or package's default.


Type: Object.

Props passed to View svelte component. You will receive these props exporting each property in the view.


Type: Object.

Props passed global context accessible via getContext('global.props').


Type: Object.

Props passed global store accessible via getContext('global.stores').

Props, global props and global stores logic and behavior

For props, each property can be accessed via export let propertyName. You can use defaults too.

If you need to make data available globally to all components in the view you can set your values at:

For globalProps accessed via getContext('global.props'):

For globalStores accessed via getContext('global.stores'):

  • The engine will create a svelte store for every first level value of the globalStores provided object.

Express example:

res.render('View', {
    props: {
        localValue: 1 
    globalProps: {
        title: 'Some title!'
    globalStores: {
        user: { name: 'John' },
        session: { sessionValue: 2 }

Svelte example: View.svelte

    import { getContext } from 'svelte';
    const { title } = getContext('global.props');  
    const { user, session } = getContext('global.stores');
    export let localValue = null;




The variables it receives are:

  • head: Output from <svelte:head> component.
  • style: CSS code.
  • globalProps: Serialized global props.
  • globalStore: Serialized global store.
  • props: View props.
  • script: Script url.
  • scriptLegacy: Script url of legacy build.
  • scriptModern: Script url of modern build.
  • hydratable: Boolean indicating if the view is hydratable.
  • legacy: Boolean indicating if legacy support is enabled.
  • html: HTML code.

Also @nuxt/devalue function is provided to serialize props. This is made at template level to avoid serializing props that are not necessary according to hydration config.

Top categories

svelte logo

Want a Svelte site built?

Hire a Svelte developer
Loading Svelte Themes