From fb4421bb05ef951b6b26fc5815571d82fb505a08 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 12 Jun 2026 20:50:32 +0530 Subject: [PATCH 1/3] Add build cache blog post --- .optimize-cache.json | 1 + .../+page.markdoc | 86 ++++++++++++++++++ .../install-times.avif | Bin 0 -> 21258 bytes 3 files changed, 87 insertions(+) create mode 100644 src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc create mode 100644 static/images/blog/inside-appwrites-new-build-cache/install-times.avif diff --git a/.optimize-cache.json b/.optimize-cache.json index f121a447ba..fc22f8a2d6 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -789,6 +789,7 @@ "static/images/blog/init-recap-august/newcli.png": "d25380abdf625bddd5ee4c87ba2eafce19a075fa7cac7a47aa9d5b50302d3ea0", "static/images/blog/init-recap-august/product-update.png": "5e4f3c3bc35310dfd17d8623d8f6b803be1d74f696c340e1a843a39e99103690", "static/images/blog/init-recap-august/release.png": "8adb887f7db7cf6d72e1a828a3568036420e27210bae506261353ea9e120938c", + "static/images/blog/inside-appwrites-new-build-cache/install-times.png": "8aad23378d7dca56267ceda0ecdbeccc18879045f6dbba674bc473b363000c88", "static/images/blog/integrate-custom-auth-sveltekit/cover.png": "9d4f5a28e04678300566038a11c91021b806eead6b9ecdad870f968cf09aa9cf", "static/images/blog/integrate-custom-auth-sveltekit/overview.png": "a13879174eece52967372d0312725cd2f360a9e312425b68cba50aaffcd12558", "static/images/blog/integrate-resend-smtp/api-key.png": "75edc5610ca8f571a70396f9e25c6132f26065440cc837af95102de4b8408708", diff --git a/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc b/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc new file mode 100644 index 0000000000..41e30c19f4 --- /dev/null +++ b/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc @@ -0,0 +1,86 @@ +--- +layout: post +title: "Inside Appwrite's new build cache: 4x faster dependency installs" +description: A deep dive into how Appwrite now caches your dependencies between builds, and what it means for your deployment times. +date: 2026-06-12 +cover: /images/blog/inside-appwrites-new-build-cache/cover.png +timeToRead: 7 +author: eldad-fux +category: engineering +featured: false +faqs: + - question: "What does Appwrite's build cache store?" + answer: "It stores your package manager's content-addressable stores, such as the pnpm store, between builds. The cache is packed into a single compressed SquashFS image, saved to storage after a successful build, and restored before the next one. Your project files and node_modules are rebuilt fresh every time." + - question: "Do I need to configure anything to use the build cache?" + answer: "No. The cache is keyed automatically per site or function, and your install command works unchanged. If no cache exists yet, the build runs exactly as before and saves a snapshot for next time." + - question: "Which package managers benefit the most?" + answer: "pnpm and bun see the biggest wins because they link packages from a content-addressable store instead of unpacking archives, so a restored store turns installs into a fast linking pass. npm and yarn caches are also covered." + - question: "Can a broken cache fail my build?" + answer: "No. The cache is best-effort by design. If a restore or save fails for any reason, the build continues without it, exactly as if the cache did not exist." +--- + +Every deployment on Appwrite builds inside a fresh, isolated environment. That isolation is great for reproducibility and security, but it comes with a tax: the build starts with an empty disk, with nothing carried over from previous builds, so your `pnpm install` re-downloads every package on every deployment, even if you only changed one line of code. + +We have now removed that tax. Appwrite's build network caches your dependencies between builds, and restoring them is fast enough that installs on a real-world Next.js app drop from 11.7 to 2.8 seconds with pnpm, and from 9.6 to 2.3 seconds with bun. + +![Dependency install times with the new build cache](/images/blog/inside-appwrites-new-build-cache/install-times.avif) + +Let's look at how it works under the hood. + +# The problem with clean builds + +When you deploy a site or function, Appwrite spins up a dedicated container for the build, runs your install and build commands, uploads the result, and throws the container away, so by design nothing survives between builds. + +For dependencies, that means the same work repeats every time. A typical production Next.js app pulls in hundreds of packages, and on every deployment your package manager resolves them, downloads them from the registry, and assembles `node_modules` from scratch. For the app we will use as an example throughout this post, that is roughly 650 packages re-downloaded for every one-line change. + +# What we built + +The build environment now mounts a small cache volume, and the build pipeline does three extra things: + +1. **Before your install command runs**, Appwrite checks storage for a cache snapshot belonging to your site or function. If one exists, it is downloaded and unpacked into the package manager's store locations. +2. **Your build runs unchanged.** The package manager finds its store already populated and skips the registry almost entirely. +3. **After a successful build**, the updated store is packed and saved back to storage, so the next build benefits from anything new this one downloaded. + +The cache is keyed per resource, so different sites and functions never share snapshots, and a new resource always starts clean. + +# Why SquashFS + +Package manager stores are the worst case for storage systems: tens of thousands of tiny files. Moving them to object storage one by one would drown in per-file overhead, and a classic `tar.gz` archive is slow to unpack because gzip is single-threaded and extraction creates files strictly in sequence. + +Instead, we pack the store into a single [SquashFS](https://docs.kernel.org/filesystems/squashfs.html) image, the same compressed, read-only filesystem format Linux live systems boot from. This gives us three properties we wanted: + +- **Fast compression** that decompresses at multiple gigabytes per second, so unpacking is never the bottleneck. +- **Parallel packing and unpacking** that uses every core available to the build container. +- **One file means one storage request.** Restoring the cache is a single read, saving it is a single write. + +# The numbers + +We measured the cache with a Next.js application using 23 production dependencies, deployed through the Appwrite CLI, once with pnpm and once with bun. + +With pnpm: + +- **First build (no snapshot):** all 641 packages are downloaded from the registry, and the install completes in **11.7 seconds**. +- **Every build after:** the snapshot is restored before `pnpm install` runs, and the same install completes in **2.8 seconds**. + +With bun: + +- **First build:** 646 packages installed in **9.6 seconds**. +- **With a warm cache:** **2.3 seconds**. + +That is a 4.2x speedup for both package managers, with zero configuration changes in either case. + +The split between those two numbers also tells you where install time actually goes. A warm install does everything a cold one does except talk to the registry, so the difference between the two runs is pure download time: + +- **pnpm:** about 9 of the 11.7 cold-install seconds were downloads, leaving 2.8 seconds of lockfile resolution and linking. +- **bun:** about 7.3 of its 9.6 seconds were downloads, leaving 2.3 seconds of linking. + +The cache removes the download share entirely. The reason the remaining work is so small is that pnpm links packages out of a single [content-addressable store](https://pnpm.io/motivation) and bun uses a similar [global cache](https://bun.sh/docs/install/cache) with hardlinks, instead of unpacking an archive for every package. With the store restored from the snapshot, an install becomes a linking pass over files that are already on disk. + +The build cache is live across the Appwrite network. Deploy a site or function, and from your second build onward, your installs are already faster. + +# Resources + +- [Appwrite Sites docs](/docs/products/sites) +- [Appwrite Functions docs](/docs/products/functions) +- [Deploy sites from the CLI](/docs/tooling/command-line/sites) +- [pnpm's content-addressable store](https://pnpm.io/motivation) diff --git a/static/images/blog/inside-appwrites-new-build-cache/install-times.avif b/static/images/blog/inside-appwrites-new-build-cache/install-times.avif new file mode 100644 index 0000000000000000000000000000000000000000..b5f4d53e4656d9c37fe495bc1e8912f7cb4a3bc9 GIT binary patch literal 21258 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 Date: Fri, 12 Jun 2026 20:51:55 +0530 Subject: [PATCH 2/3] Move benchmark chart into The numbers section --- .../blog/post/inside-appwrites-new-build-cache/+page.markdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc b/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc index 41e30c19f4..5e16562b9b 100644 --- a/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc +++ b/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc @@ -23,8 +23,6 @@ Every deployment on Appwrite builds inside a fresh, isolated environment. That i We have now removed that tax. Appwrite's build network caches your dependencies between builds, and restoring them is fast enough that installs on a real-world Next.js app drop from 11.7 to 2.8 seconds with pnpm, and from 9.6 to 2.3 seconds with bun. -![Dependency install times with the new build cache](/images/blog/inside-appwrites-new-build-cache/install-times.avif) - Let's look at how it works under the hood. # The problem with clean builds @@ -55,6 +53,8 @@ Instead, we pack the store into a single [SquashFS](https://docs.kernel.org/file # The numbers +![Dependency install times with the new build cache](/images/blog/inside-appwrites-new-build-cache/install-times.avif) + We measured the cache with a Next.js application using 23 production dependencies, deployed through the Appwrite CLI, once with pnpm and once with bun. With pnpm: From 7a6810d37451ad240c6a4299031fa51ef7560ca2 Mon Sep 17 00:00:00 2001 From: Atharva Deosthale Date: Fri, 12 Jun 2026 20:52:48 +0530 Subject: [PATCH 3/3] Bold install numbers in intro --- .../blog/post/inside-appwrites-new-build-cache/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc b/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc index 5e16562b9b..af0e1778f6 100644 --- a/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc +++ b/src/routes/blog/post/inside-appwrites-new-build-cache/+page.markdoc @@ -21,7 +21,7 @@ faqs: Every deployment on Appwrite builds inside a fresh, isolated environment. That isolation is great for reproducibility and security, but it comes with a tax: the build starts with an empty disk, with nothing carried over from previous builds, so your `pnpm install` re-downloads every package on every deployment, even if you only changed one line of code. -We have now removed that tax. Appwrite's build network caches your dependencies between builds, and restoring them is fast enough that installs on a real-world Next.js app drop from 11.7 to 2.8 seconds with pnpm, and from 9.6 to 2.3 seconds with bun. +We have now removed that tax. Appwrite's build network caches your dependencies between builds, and restoring them is fast enough that installs on a real-world Next.js app drop from **11.7s → 2.8s** with pnpm, and from **9.6s → 2.3s** with bun. Let's look at how it works under the hood.