diff --git a/k8s/absd.yaml b/k8s/absd.yaml
index 0886fd57178dc80e9627331a4b59d54c1d2ed795..2a097309ecb77bde3685bcd83b51e2e9ff8683ae 100644
--- a/k8s/absd.yaml
+++ b/k8s/absd.yaml
@@ -63,9 +63,9 @@ spec:
             httpGet:
               path: /ready
               port: 3000
-            initialDelaySeconds: 30
-            periodSeconds: 30
-            timeoutSeconds: 5
+            initialDelaySeconds: 0
+            periodSeconds: 5
+            timeoutSeconds: 2
             failureThreshold: 5
           resources:
             requests:
diff --git a/src/client/api.ts b/src/client/api.ts
index 666d89893cf47ac7060361c0a8ee1c7e355297c3..515656503ec0bc2eeedf784744a2f39444058304 100644
--- a/src/client/api.ts
+++ b/src/client/api.ts
@@ -69,5 +69,8 @@ export default Object.freeze({
   },
   archiveURL: (archiveName: string): string => {
     return `/api/downloads/${archiveName}`
+  },
+  databaseIsReady: async (): Promise<AxiosResponse<any>> => {
+    return await base.get('/api/readyDatabase')
   }
 })
diff --git a/src/client/components/App.vue b/src/client/components/App.vue
index 6503fb9a969ee8981b13c636bcaeac30e8310dab..79657acfe231035b5b72e8ca529390ecfc7540ad 100644
--- a/src/client/components/App.vue
+++ b/src/client/components/App.vue
@@ -14,14 +14,23 @@
 
 <script setup lang="ts">
 import { onMounted } from 'vue'
-import { useStore } from '../store'
 import AppFooter from './AppFooter.vue'
 import AppHeader from './AppHeader.vue'
+import router from '../router'
+import api from '../api'
+import { AxiosError } from 'axios'
 
-const store = useStore()
-
-onMounted(() => {
-  store.getStatistics()
+onMounted(async () => {
+  await api.databaseIsReady()
+    .then()
+    .catch((err: AxiosError) => {
+      if (err.status === 503) {
+        router.replace({ name: 'WaitingPage' })
+      } else {
+        alert(err.message)
+        console.log(err)
+      }
+    })
 })
 </script>
 
diff --git a/src/client/components/AppTitle.vue b/src/client/components/AppTitle.vue
new file mode 100644
index 0000000000000000000000000000000000000000..8eaedf77c205a35df0a4291da8bbd41b54d8bb46
--- /dev/null
+++ b/src/client/components/AppTitle.vue
@@ -0,0 +1,20 @@
+<template>
+  <h1>
+    <img
+      src="/absd-title.png"
+      alt="ABSD logo with title"
+      height="90"
+      width="325">
+    <span class="title-for-a11y">
+      ABSD - AntiBody Sequence database
+    </span>
+  </h1>
+</template>
+
+<script setup lang="ts"></script>
+
+<style scoped>
+.title-for-a11y {
+  display: none;
+}
+</style>
diff --git a/src/client/components/The404Page.vue b/src/client/components/The404Page.vue
index b7e40624d18c6e7f1f938076a19f993338aa7802..144831c76f951ebca356928df6d2c99b8bbf2b1f 100644
--- a/src/client/components/The404Page.vue
+++ b/src/client/components/The404Page.vue
@@ -1,17 +1,33 @@
 <template>
-  <h1>404 - Not Found</h1>
-  <p>The page or resource you requested doesn't seem to exist here...</p>
+  <AppTitle></AppTitle>
+  <section>
+    <h2>404 - Not Found</h2>
+    <p>The page or resource you requested doesn't seem to exist here...</p>
+    <RouterLink :to="{ name: 'HomePage' }">
+      Go back home
+    </RouterLink>
+  </section>
 </template>
 
 <script setup lang="ts">
+import AppTitle from './AppTitle.vue'
 </script>
 
 <style scoped>
+section {
+  display: flex;
+  flex-flow: column;
+  align-items: center;
+  gap: var(--spacing);
+}
+
+h2,
 p {
   text-align: center;
 }
 
-p {
+a, p {
   font-size: 20px;
+  margin-top: 0;
 }
 </style>
diff --git a/src/client/components/TheHomePage.vue b/src/client/components/TheHomePage.vue
index d81ccf518dc22630ddbb8faae7d0443b4e35e3a0..11f92be7eea4eefdce8cf47c9f9013a2a84febab 100644
--- a/src/client/components/TheHomePage.vue
+++ b/src/client/components/TheHomePage.vue
@@ -1,15 +1,5 @@
 <template>
-  <h1>
-    <img
-      src="/absd-title.png"
-      alt="ABSD logo with title"
-      height="90"
-      width="325"
-    >
-    <span class="title-for-a11y">
-      ABSD - AntiBody Sequence database
-    </span>
-  </h1>
+  <AppTitle></AppTitle>
 
   <section class="page-description">
     <p>
@@ -141,6 +131,7 @@
 <script setup lang="ts">
 import { computed, onMounted } from 'vue'
 import { useStore } from '../store'
+import AppTitle from './AppTitle.vue'
 import AntibodiesTable from './AntibodiesTable.vue'
 import NoResults from './NoResults.vue'
 import SearchBar from './SearchBar.vue'
@@ -154,8 +145,10 @@ const versionDate = computed(() => { return store.antibodiesVersionDate })
  * give the user a preview of what to expect after a search.
  */
 onMounted((): void => {
-  store.fetchAntibodies(store.request.fetchParams())
-  store.countAntibodies(store.request.countParams())
+  store.getStatistics().then(() => {
+    store.fetchAntibodies(store.request.fetchParams())
+    store.countAntibodies(store.request.countParams())
+  })
 })
 </script>
 
diff --git a/src/client/components/TheWaitingPage.vue b/src/client/components/TheWaitingPage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..eaf174bb744663f73f5b0ee740cdd979e52169cf
--- /dev/null
+++ b/src/client/components/TheWaitingPage.vue
@@ -0,0 +1,72 @@
+<template>
+  <AppTitle></AppTitle>
+
+  <section>
+    <p>
+      The Database is currently being updated,
+      please come back in a few minutes.
+    </p>
+
+    <div class="spinner"></div>
+  </section>
+</template>
+
+<script setup lang="ts">
+import { onMounted, onUnmounted } from 'vue'
+import AppTitle from './AppTitle.vue'
+import api from '../api'
+import { AxiosError } from 'axios'
+import router from '../router'
+
+/** ID of the interval timer started on page load */
+let intervalID: number
+
+/**
+ * After page load, check for database readiness immediately
+ * and every 5 seconds.
+ */
+onMounted(() => {
+  checkDatabaseIsReady()
+  intervalID = setInterval(checkDatabaseIsReady, 5000)
+})
+
+/**
+ * Remove the timer when leaving the page to ensure
+ * memory safety.
+ */
+onUnmounted(() => {
+  clearInterval(intervalID)
+})
+
+/**
+ * Check is the database is ready and reroute to
+ * the home page in that case.
+ */
+function checkDatabaseIsReady() {
+  api.databaseIsReady()
+    .then(() => {
+      router.replace({ name: 'HomePage' })
+    })
+    .catch((err: AxiosError) => {
+      if (err.status === 503) return
+      else {
+        alert(err.message)
+        console.log(err)
+      }
+    })
+}
+</script>
+
+<style scoped>
+section {
+  align-items: center;
+  display: flex;
+  flex-flow: column wrap;
+  gap: var(--spacing);
+}
+
+.spinner {
+  height: 50px;
+  width: 50px;
+}
+</style>
diff --git a/src/client/router.ts b/src/client/router.ts
index 6636662a552b9e6bd0fbe93da0feded1a5181d01..0e6d020b67548bad8fa68a83d6664759fb822220 100644
--- a/src/client/router.ts
+++ b/src/client/router.ts
@@ -51,6 +51,11 @@ export default createRouter({
       component: async () => await import('./components/TheAboutPage.vue'),
       name: 'AboutPage'
     },
+    {
+      path: '/waiting',
+      component: async () => await import('./components/TheWaitingPage.vue'),
+      name: 'WaitingPage'
+    },
     {
       path: '/:pathMatch(.*)*',
       component: async () => await import('./components/The404Page.vue'),
diff --git a/src/client/store.ts b/src/client/store.ts
index 402666a3012f542cfcdcb98cb0fda0976716f83e..e003d5e0cd8d2b90368418d4f85671f3c51d4809 100644
--- a/src/client/store.ts
+++ b/src/client/store.ts
@@ -170,8 +170,8 @@ export const useStore = defineStore('store', {
      * Get the database statistics from the server and stores it in the
      * corresponding variable in the store.
      */
-    getStatistics(): void {
-      api.getStatistics().then(response => {
+    getStatistics(): Promise<void> {
+      return api.getStatistics().then(response => {
         this.statistics = Object.freeze(response.data)
       }).catch((err: AxiosError) => {
         alert(err.message)
diff --git a/src/server/app.js b/src/server/app.js
index ac0adf5803e008023db408782618f603b13c5e76..8465c03daf4c9c3198f60a4bbe8385b0f7fcccd2 100644
--- a/src/server/app.js
+++ b/src/server/app.js
@@ -36,6 +36,7 @@ import downloadsFileRoute from './routes/downloadsFileRoute.js'
 import downloadsRoute from './routes/downloadsRoute.js'
 import healthCheckRoute from './routes/healthCheckRoute.js'
 import readyCheckRoute from './routes/readyCheckRoute.js'
+import readyDatabaseRoute from './routes/readyDatabaseRoute.js'
 import statisticsRoute from './routes/statisticsRoute.js'
 
 /**
@@ -86,9 +87,10 @@ fastify.register(fastifyMongo, {
 // Route controllers
 // =========================================================================
 
-// Decorate the server with a boolean marking when it is ready.
-// Used by the readyCheck route.
+// Decorate the server with booleans marking when resources are ready.
+// Used by the readiness routes.
 fastify.decorate('serverIsReady', false)
+fastify.decorate('databaseIsReady', true)
 
 // Decorate the server with an object
 // to store the workers while then run.
@@ -101,7 +103,7 @@ fastify.addHook('onRequest', async (request) => {
   request.where = {}
 })
 
-// Register all controllers
+// Register all API controllers
 fastify.route(antibodiesCountRoute)
 fastify.route(antibodiesDownloadArchiveFileRoute)
 fastify.route(antibodiesDownloadArchiveRoute)
@@ -114,6 +116,9 @@ fastify.route(antibodiesVGeneSegmentsRoute)
 fastify.route(downloadsFileRoute)
 fastify.route(downloadsRoute)
 fastify.route(statisticsRoute)
+fastify.route(readyDatabaseRoute)
+
+// Register health checks
 fastify.route(healthCheckRoute)
 fastify.route(readyCheckRoute)
 
@@ -164,15 +169,19 @@ fastify.listen({
   host: envConfig.ABSD_SERVER_HOST,
   port: envConfig.ABSD_SERVER_PORT
 }).then(async () => {
+  fastify.serverIsReady = true
+  fastify.log.info({ envConfig })
+
   if (envConfig.NODE_ENV === 'production') {
+    fastify.databaseIsReady = false
     return await buildDatabase()
   }
 }).then((dbResults) => {
   if (dbResults) {
     fastify.log.info(`${envConfig.ABSD_DB_NAME} database created`)
   }
-  fastify.log.info({ envConfig })
-  fastify.serverIsReady = true
+
+  fastify.databaseIsReady = true
 }).catch(err => {
   fastify.log.error(err)
   process.exit(1)
diff --git a/src/server/routes/readyDatabaseRoute.js b/src/server/routes/readyDatabaseRoute.js
new file mode 100644
index 0000000000000000000000000000000000000000..9998ae593a0f3308a21ed44d391281b34ac17fe3
--- /dev/null
+++ b/src/server/routes/readyDatabaseRoute.js
@@ -0,0 +1,36 @@
+// ABSD
+// Copyright (C) 2025 Institut Pasteur
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Route returning if the database is available or not.
+ * False when the database is inserting data.
+ */
+export default {
+  method: 'GET',
+  url: '/api/readyDatabase',
+  logLevel: 'warn',
+  handler: function (request, reply) {
+    if (this.databaseIsReady) {
+      return reply
+        .code(200)
+        .send({ ready: true })
+    }
+
+    return reply
+      .code(503)
+      .send({ ready: false })
+  }
+}