Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SvelteKit Maintenance Mode

Is there a good way to do display a maintenance page when visiting any route of my SvelteKit website?

My app is hosted on Vercel, for those who want to know.

What I've tried so far:

  • Set an environment variable called MAINTENANCE_MODE with a value 1 in Vercel.
  • For development purposes I've set this in my .env file to VITE_MAINTENANCE_MODE and called with import.meta.env.VITE_MAINTENANCE_MODE.

Then inside +layout.server.js I have the following code to redirect to /maintenance route

import { redirect } from "@sveltejs/kit";

export async function load({ url }) {
  const { pathname } = url;

  // Replace import.meta.env.VITE_MAINTENANCE_MODE with process.env.MAINTENANCE_MODE in Production
  if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
    if (pathname == "/maintenance") return;
    throw redirect(307, "/maintenance");
  } else {
    if (pathname == "/maintenance") {
      throw redirect(307, "/");
    };
  };
};

What I've also tried is just throwing an error in +layout.server.js with the following:

import { error } from "@sveltejs/kit";

export async function load() {
  if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
    throw error(503, "Scheduled for maintenance");
  };
};

However this just uses SvelteKit's static fallback error page and not +error.svelte. I've tried creating src/error.html in the hope to create a custom error page for +layout.svelte but couldn't get it to work. I would like to use a custom page to display "Down for maintenance", but I don't want to create an endpoint for every route in my app to check if the MAINTENANCE_MODE is set to 1.

Any help is appreciated

like image 979
DogFoxX Avatar asked Feb 24 '26 07:02

DogFoxX


1 Answers

You could use a handle server hook, e.g. src/hooks.server.ts:

import { env } from '$env/dynamic/private';
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
    if (env.MAINTENANCE_MODE == '1' && event.route.id != '/maintenance')
        return new Response(undefined, { status: 302, headers: { location: '/maintenance' } });

    // <other logic>
    
    // Default response
    return await resolve(event);
}

And on the maintenance page you can prevent all further navigation:

import { beforeNavigate } from '$app/navigation';

beforeNavigate(async ({ cancel }) => {
    cancel();
});

(Possibly add some periodic checks via fetch calls to navigate elsewhere once the site is back online.)

like image 179
H.B. Avatar answered Feb 27 '26 01:02

H.B.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!