Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d3dad38
feat: add mor information on reduction and cold start improvements
levivannoort Mar 16, 2026
3e81d28
chore: improve readability
levivannoort Mar 17, 2026
aeab617
chore: add another paragraph about next steps
levivannoort Mar 17, 2026
c1a717b
chore: setup naming
levivannoort Mar 17, 2026
308b47d
feat: add banner, avatar and roundup the blog post
levivannoort Mar 18, 2026
dc75779
Merge branch 'main' into CLO-4110
levivannoort Mar 18, 2026
7bf0c31
Apply suggestion from @greptile-apps[bot]
adityaoberai Mar 19, 2026
c3ed91d
chore: remove anchor
levivannoort Mar 24, 2026
2db7131
chore: update avatar and the results of the template testing
levivannoort Apr 21, 2026
60bed63
Merge branch 'main' into CLO-4110
levivannoort Apr 21, 2026
5739c65
chore: update usage of raw tar
levivannoort Apr 21, 2026
d05a9b2
chore: add images and option around image resizing to prevent it look…
levivannoort Apr 21, 2026
9d098e0
chore: clear up references
levivannoort Apr 21, 2026
f48cb0c
chore: update with eline of text between the table and the observabil…
levivannoort Apr 21, 2026
a3ac70f
chore: downscale
levivannoort Apr 21, 2026
cb12ff3
chore: fix the format and assets tests
levivannoort Apr 21, 2026
e85dcb6
chore: optimize images
levivannoort Apr 21, 2026
a9e4b94
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
f28eb02
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
bc78f1d
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
47c71d0
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
fe86bcd
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
1d1da1d
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
95f1bd0
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
412f68e
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
a0e6f9e
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
ce117ee
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
levivannoort Apr 22, 2026
b159142
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
adityaoberai Apr 23, 2026
683f192
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
adityaoberai Apr 23, 2026
27a062a
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
adityaoberai Apr 23, 2026
8ae4f55
Update src/routes/blog/post/reducing-cold-starts-appwrite-sites/+page…
adityaoberai Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .optimize-cache.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"images/avatars/jesse.png": "99f96274279be20c2bf6c97feeef9f61b7fb8bde6404b4f2472cfd63b44f6cdf",
"images/avatars/kushboo.png": "b64531c4b946dfe64c542c7d400a431c8b6634b1bfafda5cd293ba14407a80b6",
"images/avatars/laura.png": "608a5ca230d0dbd4fbedac4c9f3b6203f1e70108c3da697d79e2f13a607d7d33",
"images/avatars/levi.png": "10d2a7a99d47a969ed74aa0ddc014f985e3d3904f086e83abf56978482b2d8b0",
"images/avatars/luke.png": "d3945fa606673bcef524da2736fa27bc4a4ee75e8b188a80b1e7d511f4def350",
"images/avatars/matej.png": "5b456bf1472486f98610cb8f76c3aacc1fa413b8486b5b119639d2dacc700187",
"images/avatars/may.png": "b060895e3a13de66ba4834177643fec8ec700a18eaeee56d5d12ad58ff103f7b",
Expand Down Expand Up @@ -896,6 +897,9 @@
"images/blog/react-protected-routes/cover.png": "0b9257f28c839295b8f31f382cb71e151729abb0ce02625b4f0bf2a67899a005",
"images/blog/reasons-to-run-your-ci-pipeline-on-appwrite/cover.png": "acc0bd5633739773a0641e8adaf2cbf0b3f88f504c5407801d155b507f055fbd",
"images/blog/receipt-scan.png": "475fba54e52031f8b05a759bfe65ed54c1aa52a64283a47c27fb20c8dfbf4b3d",
"images/blog/reducing-cold-starts-appwrite-sites/build-output-sizes-nft.png": "19f7c37c248fa871786fd8a47064475520e4dcb1df36c996871f3983fcd72495",
"images/blog/reducing-cold-starts-appwrite-sites/build-output-sizes-non-nft.png": "8b814c3736045e286e95e0866f7d61ae589ab8492985edce7c6b23e18d84dc7e",
"images/blog/reducing-cold-starts-appwrite-sites/cover.png": "17a950964dddaaafab1461ee0dbecd6170f4002d357ecdbd7e2152028a39f63e",
"images/blog/remix-3-whats-changing-and-why-it-matters/cover.png": "258303cffbe98e2b76642220c091492f0c77cfedcd1989167a92683709f5f38d",
"images/blog/rest-vs-graphql-websockets/cover.png": "74e82a5592d964caac5425b6846c0c361e5f516867f8feaf5b2baca9b7e69860",
"images/blog/rethinking-saas-authentication/cover.png": "0240c259c4ab551f07c6a3c7ace5768fe6842b33e6509e34ae624e47d9308d40",
Expand Down
15 changes: 12 additions & 3 deletions src/markdoc/nodes/Image.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

let { src, alt, title }: ImageProps = $props();

const contain = $derived(title === 'contain');
const resolvedTitle = $derived(contain ? undefined : title);

const inTable = isInTable();
const isAudio = $derived(/\.(wav|mp3|m4a|ogg)$/i.test(src));

Expand All @@ -38,11 +41,17 @@
Your browser does not support the audio element.
</audio>
{:else}
<img {src} {alt} {title} loading="lazy" style:vertical-align="middle" />
<img {src} {alt} title={resolvedTitle} loading="lazy" style:vertical-align="middle" />
{/if}
{:else}
<span class="web-media relative my-8! block">
<img {src} {alt} {title} loading="lazy" class="aspect-video w-full object-cover" />
<img
{src}
{alt}
title={resolvedTitle}
loading="lazy"
class="w-full {contain ? '' : 'aspect-video object-cover'}"
/>
<span class="absolute right-4 bottom-4 opacity-25 transition hover:opacity-100">
<Tooltip closeOnPointerDown>
<Button variant="secondary" class="cursor-pointer" action={trigger}>
Expand All @@ -64,7 +73,7 @@
use:melt={$content}
{src}
{alt}
{title}
title={resolvedTitle}
loading="lazy"
transition:scale={{ duration: 150, start: 0.95, easing: quadInOut }}
/>
Expand Down
9 changes: 9 additions & 0 deletions src/routes/blog/author/levi-van-noort/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
layout: author
name: Levi van Noort
slug: levi-van-noort
role: Platform Engineer
bio: Building a stable and standardized platform.
avatar: /images/avatars/levi.png
---

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
layout: post
title: "How we reduced cold start times on Appwrite Sites"
description: Learn how we improved cold-start performance for Appwrite Sites, delivering faster load times for your web applications.
date: 2026-04-24
cover: /images/blog/reducing-cold-starts-appwrite-sites/cover.png
timeToRead: 5
author: levi-van-noort
category: product
---

If you've ever deployed a site and noticed that first request taking just a bit too long, you've experienced a cold start. It's one of those things that's easy to overlook during development but quickly becomes noticeable in production, especially when your users are the ones waiting.

At Appwrite, improving the performance of [Sites](/products/sites) (and every other product) has always been a high priority. We wanted that first request to feel just as fast as every request after it. So we dug into the problem, ran some experiments, and made a series of changes that significantly brought down cold-start times.

In this blog, we will walk you through the cause of the slowdown, the approach we took to fix it, and the results we have seen since.

# Adding observability

Before implementing any fixes, we needed to understand what was actually happening. We started by adding observability across the full request lifecycle, instrumenting every step from the moment a request hits our edge to when the response is sent back. This gave us a clear breakdown of where time was being spent (and where it was being wasted). Without that visibility, we would have been guessing, and in performance work, guessing is how you end up optimizing the wrong thing.

# Compression and decompression

With better visibility into the request lifecycle, one pattern stood out immediately: compression and decompression of the build output accounted for a significant share of cold-start time. Build artifacts were being compressed with tar and extracted with gzip. This worked fine functionally, but the extraction step was eating up a noticeable chunk of every first request.

We tested a drop-in replacement of gzip with [igzip](https://github.com/intel/isa-l), an optimized implementation from Intel's Intelligent Storage Acceleration Library. The results were immediate: extraction times improved by 50 to 100%, making it one of the highest-impact changes we shipped. We also evaluated [zstd](https://github.com/facebook/zstd) as an alternative, but its performance was more variable and only showed gains at certain build output sizes, so we stuck with igzip for its consistent wins across the board. For very small build outputs, we skipped compression entirely and used plain tar, avoiding any decompression cost on the download path.

# Node file tracing

Faster decompression was a big win, but it raised an obvious next question: why were we extracting so much in the first place? Many build outputs included dependencies and files that were never touched at runtime. To address this, we implemented [Node file tracing](https://github.com/vercel/nft), which statically analyzes a Node.js application to determine exactly which files are required to run it.

The impact was dramatic. Smaller artifacts meant less to compress, less to transfer, and less to extract, compounding the gains we had already made on the decompression side.

Here are some examples of size reductions across our templates:

| Templates | Before | After | Reduction |
| --------- | ------ | ----- | --------- |
| Nuxt Playground | 235 MB | 46 MB | 80.4% |
| Analog Playground | 858 MB | 10 MB | 98.8% |
| TanStack Starter | 323 MB | 49 MB | 84.8% |
| Astro Playground | 169 MB | 95 MB | 43.8% |
| Remix Playground | 234 MB | 7 MB | 97.0% |
| Svelte Starter | 103 MB | 13 MB | 87.4% |
| Store Template | 185 MB | 3.5 MB | 98.1% |

The reduction in build output size also showed up clearly in our observability data:

![build-output-sizes](/images/blog/reducing-cold-starts-appwrite-sites/build-output-sizes-non-nft.png "contain")

![build-output-sizes](/images/blog/reducing-cold-starts-appwrite-sites/build-output-sizes-nft.png "contain")

# Cold starts
Comment thread
levivannoort marked this conversation as resolved.

Those smaller artifacts translated directly into faster cold starts. With build outputs reduced by up to 98.8%, the download phase, previously one of the more costly steps, dropped from multiple seconds to just 100 to 200 milliseconds. Extraction saw a similar improvement, going from regular 4 to 7 second spikes down to around 200 to 400 milliseconds. Together, these two phases went from dominating the cold-start timeline to being barely noticeable.

The overall effect was a roughly 30 to 50% reduction in cold-start duration across the board. The remaining time is now largely spent on runtime initialization rather than transferring and unpacking artifacts. We've shifted the bottleneck to a fundamentally different part of the stack, and that's exactly where we want to focus next. With targeted work there, we expect to bring P95 timings below what P50 used to be.

# Benefit from this change

If you're running an SSR-based site on Appwrite Sites, all you need to do is redeploy your latest active deployment. The updated build process will automatically apply the optimizations described above, reducing your build output size and improving cold-start times, with no code changes required.

# What's next

These improvements are just the beginning. We're actively working on the next round of optimizations. Performance is not a one-time fix; it's an ongoing effort, and we're committed to making every deploy on Appwrite Sites feel instant. [Stay tuned](https://appwrite.io/discord) for more updates as we continue to push cold start times even lower.
Binary file added static/images/avatars/levi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading