GitHubRSS Feed
Runtime Environment Variables for SvelteKit SSR

Runtime Environment Variables for SvelteKit SSR

Explanation

In order to get runtime variables injected into the frontend we need to use sveltekit's endpoints. Because code is running on both the server and the client we can't use process.env like we normally would in a node application. For my website I needed my api url and some set up variables for application monitoring. I want runtime variables because we DO NOT BUILD PER ENVIRONMENT. Vite's dotenv implementation allows you to bake variables into the app during build time, but we deploy things properly so this won't work for us.

Note

Creating the Endpoint

Create a file called appsettings.json.ts in the routes folder, this will be our endpoint. Export the get function and  return some environment variables with sensible defaults for development.

// routes/appsettings.json.ts

export async function get() : Promise<{body: any}> {

	return {
        body: {
            ENVIRONMENT: process.env["ENVIRONMENT"] || "development",
            DISPLAY_ENVIRONMENT: process.env["DISPLAY_ENVIRONMENT"] || true,
        }
    };
}

Now let's define the return type and do some cool type manipulation. I need a boolean from an environment variable, which are strings, so I'll create a function to handle this.

// routes/appsettings.json.ts

type Appsettings = {
    ENVIRONMENT: string,
    DISPLAY_ENVIRONMENT: boolean
}

export async function get() : Promise<{body: Appsettings}> {
    const toBool = (variable : string) : boolean => {
        if (variable && variable.toLowerCase() === "true") {
            return true;
        }
        return false;
    }

	return {
        body: {
            ENVIRONMENT: process.env["ENVIRONMENT"] || "development",
            DISPLAY_ENVIRONMENT: toBool(process.env["DISPLAY_ENVIRONMENT"]) || false
        }
    };
}

Using the Endpoint

In the root __layout.svelte file we'll consume our endpoint and cache our configuration in a store to be used elsewhere in our app.

// routes/__layout.svelte

<script lang="ts" context="module">
	export async function load({ fetch }) {
		const url = '/appsettings.json';
		const res = await fetch(url);
		if (res.ok) {
			return {
				props: {
					APPSETTINGS: await res.json()
				}
			};
		}
		return {
			status: res.status,
			error: new Error('Could not load configuration')
		};
	}
</script>

<script lang="ts">
	import { appSettingsStore } from '$lib/stores/appsettings';
    
	export let APPSETTINGS;

	$appSettingsStore = APPSETTINGS;

	const {
    	ENVIRONMENT,
        DISPLAY_ENVIRONMENT
	} = $appSettingsStore;
</script>

{#if DISPLAY_ENVIRONMENT}
	<p>Running in {ENVIRONMENT}</p>
{/if}

<p>Other stuff...</p>

The example here displays the environment the app is running in if the display variable is set to true. To change the values, we change the environment variables on the server or whatever environment the app is running in (container, paas, etc.) and restart the process.

With an env file

I don't recommend using env files in production, but this will make the development workflow easy. Add a .env file with your variables.

// .env

ENVIRONMENT=development
DISPLAY_ENVIRONMENT=true

Then add the env-cmd package to import the file. We're using env-cmd over dotenv because it's a simpler change and we don't want to run the module in production.

yarn add env-cmd -D

And update your dev and preview scripts in your package.json to run env-cmd before the svelte processes.

// package.json

{
	...
	"scripts": {
        "dev": "env-cmd svelte-kit dev",
        "build": "svelte-kit build",
        "preview": "env-cmd svelte-kit preview",
        ...
    },
    ...
}

Now just run your dev, or build and preview scripts to check it out.

yarn dev

# or

yarn build
yarn preview