<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ebenezer Don</title>
    <description>The latest articles on Forem by Ebenezer Don (@ebenezerdon).</description>
    <link>https://forem.com/ebenezerdon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F253108%2F942e424e-1076-46f9-a8a1-fba59966ee98.jpg</url>
      <title>Forem: Ebenezer Don</title>
      <link>https://forem.com/ebenezerdon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ebenezerdon"/>
    <language>en</language>
    <item>
      <title>Your Experience Is Your Biggest AI Advantage</title>
      <dc:creator>Ebenezer Don</dc:creator>
      <pubDate>Fri, 20 Mar 2026 12:56:44 +0000</pubDate>
      <link>https://forem.com/ebenezerdon/your-experience-is-your-biggest-ai-advantage-1a43</link>
      <guid>https://forem.com/ebenezerdon/your-experience-is-your-biggest-ai-advantage-1a43</guid>
      <description>&lt;p&gt;AI output looks professional. That's the part people underestimate.&lt;/p&gt;

&lt;p&gt;Before these tools existed, the quality of your code reflected your experience. Junior code looked junior: inconsistent naming, missing edge cases, awkward structure. You could tell at a glance who wrote it.&lt;/p&gt;

&lt;p&gt;That's harder now. AI-generated code is clean, well-structured, properly commented, and follows conventions. A function written by someone with two years of experience, using AI, looks roughly the same as one written by someone with ten. The surface quality converged.&lt;/p&gt;

&lt;p&gt;This is exactly why experience matters more, not less. When everything looks right, the ability to &lt;a href="https://getaibook.com/blog/how-to-evaluate-ai-output" rel="noopener noreferrer"&gt;evaluate what's actually right&lt;/a&gt; becomes the scarce skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plausibility Problem
&lt;/h2&gt;

&lt;p&gt;The old failure mode was obvious. Bad code looked bad. Missing error handling showed up as missing code. Bad naming jumped off the screen. You could catch problems in review because they looked like problems.&lt;/p&gt;

&lt;p&gt;That's not how it works anymore. AI-generated code is usually clean, well-structured, and follows conventions. Often it's genuinely good. But the surface quality is high regardless of whether the underlying decisions are right. A solid implementation and one with a subtle flaw look the same on the screen. You can't tell from reading whether the query will hold at 10x load, or whether the abstraction fits where the product is heading. The code itself won't tell you.&lt;/p&gt;

&lt;p&gt;What tells you is having seen these decisions play out before. You question the error handling approach because you've spent a day hunting a bug that vanished into a catch block. You think about scaling behavior because you've watched similar queries degrade under load. You push back on the abstraction because you've lived with the cost of a similar choice in a different system.&lt;/p&gt;

&lt;p&gt;When the surface quality of everyone's code is high, the ability to evaluate what's underneath becomes the thing that separates good work from work that just looks good.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Questions You Never Think to Ask
&lt;/h2&gt;

&lt;p&gt;The biggest risk with AI is the questions you never think to ask.&lt;/p&gt;

&lt;p&gt;Someone early in their career gives the model a task and gets a working solution. They test it. It works. They ship it. What they don't do: ask what happens when the external API goes down. Ask about connection pooling under concurrent load. Ask whether the data model supports the query patterns that will exist in six months. Ask whether the rate limiter behaves correctly during a retry storm.&lt;/p&gt;

&lt;p&gt;They don't ask because they don't know to worry about these things. They haven't been the person on call when the API went down. They haven't debugged a connection pool leak that took down a service. They haven't migrated a data model that wasn't designed for the access patterns the product evolved into.&lt;/p&gt;

&lt;p&gt;The model won't raise these concerns unprompted. It answers what you ask. Your experience determines what you know to ask, and more importantly, what you know to be nervous about. That feeling when something seems too straightforward, the instinct that says "this looks too simple, what am I missing," that's years of experience surfacing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Editing Shift
&lt;/h2&gt;

&lt;p&gt;The nature of the work changed. You used to write first drafts. Now you edit generated ones.&lt;/p&gt;

&lt;p&gt;Editing is harder than writing. When you write code, you hold the full context in your head: what you're trying to do, why you chose this approach, what alternatives you considered. When you edit AI-generated code, you have to reconstruct all of that. You're reverse-engineering intent from output, then evaluating whether that intent matches what you actually need.&lt;/p&gt;

&lt;p&gt;This requires you to know more, not less. You need to understand the problem well enough to recognize when the solution misses it, know the codebase well enough to spot where generated code conflicts with existing patterns, and understand the system well enough to predict how new components will interact with everything else.&lt;/p&gt;

&lt;p&gt;The people who say "AI writes the code, I just review it" are describing a job that requires more expertise than writing it yourself. The review is the hard part. It always was. AI just made it the only part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pipeline Problem
&lt;/h2&gt;

&lt;p&gt;There's a tension in the "experience is your edge" conversation that rarely gets addressed: if AI handles the work that builds experience, where does the next generation of experienced developers come from?&lt;/p&gt;

&lt;p&gt;You don't learn what connection pooling means by reading about it. You learn it by running out of connections. You don't learn why idempotency matters by studying the concept. You learn it by processing a payment twice. The feedback loop of building, breaking, and fixing is how judgment forms.&lt;/p&gt;

&lt;p&gt;If AI handles more of the building, and the building is where the learning happens, the pipeline that creates experienced developers narrows. Juniors can ship more, faster, with fewer visible mistakes. But visible mistakes are the ones that teach you the most.&lt;/p&gt;

&lt;p&gt;This doesn't mean AI is bad for juniors. It means the path to &lt;a href="https://getaibook.com/blog/ai-didnt-make-expertise-optional" rel="noopener noreferrer"&gt;depth&lt;/a&gt; might need to be more deliberate now. If the tool handles the easy mistakes, you have to seek out the hard ones. Build things that push you into territory where AI can't carry you. Work on systems complex enough that the output needs real evaluation. The feedback loop still exists, but you might have to put yourself in its path instead of waiting for it to find you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using It or Losing It
&lt;/h2&gt;

&lt;p&gt;Experience is an advantage. A real one, not a polite reassurance. But it's conditional on two things.&lt;/p&gt;

&lt;p&gt;First, you have to actually use these tools. Judgment applied through AI is dramatically more powerful than judgment applied at the speed of manual work. If you have the depth but refuse the tools, you're competing on throughput against people who have less depth but more leverage. That's a losing position over time.&lt;/p&gt;

&lt;p&gt;Second, your experience has to be the right kind. If what you know is how to navigate a specific framework's quirks, or how to set up infrastructure from memory, or the keyboard shortcuts that make you fast, those things are getting cheaper. If what you know is how systems fail, how decisions compound, what "done well" looks like versus "done," and which &lt;a href="https://getaibook.com/blog/context-engineering-ai-skill-2026" rel="noopener noreferrer"&gt;questions to ask&lt;/a&gt; before shipping, that's the kind of experience that tells you when AI output is trustworthy and when it just looks that way.&lt;/p&gt;

&lt;p&gt;The tools are getting better. The floor is rising. The bar for "good enough without deep understanding" goes up every year. And the bar for "actually good, built to last, thought through at every level" stays exactly where it's always been: wherever your judgment puts it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>career</category>
    </item>
    <item>
      <title>How to host SSR web apps on Appwrite Sites</title>
      <dc:creator>Ebenezer Don</dc:creator>
      <pubDate>Tue, 20 May 2025 13:34:40 +0000</pubDate>
      <link>https://forem.com/appwrite/how-to-host-ssr-web-apps-on-appwrite-sites-2keb</link>
      <guid>https://forem.com/appwrite/how-to-host-ssr-web-apps-on-appwrite-sites-2keb</guid>
      <description>&lt;p&gt;When you're building a modern web app, how you serve your content matters. Some pages need to be pre-rendered ahead of time for speed. Others need to be generated dynamically on the server for personalization or real-time data. This process is called Server-Side Rendering (SSR), and Appwrite Sites supports SSR, just like it supports Client-Side Rendering (CSR) and Static Site Generation (SSG).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmh5rebvlimmcp75hpq9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmh5rebvlimmcp75hpq9r.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've used platforms like Vercel before, this will feel familiar. You can connect your GitHub repository, choose a branch, and Appwrite will build your app and deploy it to a server.&lt;/p&gt;

&lt;p&gt;In this post, we'll show you exactly how to host an SSR-capable web app using Appwrite Sites, from repository connection to framework-specific configurations. Whether you're migrating from Vercel or starting from scratch, this guide will walk you through every step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SSR, and why does it matter?
&lt;/h2&gt;

&lt;p&gt;Server-Side Rendering (SSR) means your web app's pages are rendered on the server at request time. Unlike pre-rendered static pages, SSR allows your app to respond to each request with dynamic content that's fully rendered before it reaches the browser. It's a powerful approach for apps that need authentication, personalization, real-time data, or SEO-friendly dynamic content.&lt;/p&gt;

&lt;p&gt;Appwrite Sites supports SSR by allowing you to configure your framework's build settings and output behavior, and by running your app on a server runtime (Node.js) where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting an SSR app on Appwrite Sites
&lt;/h2&gt;

&lt;p&gt;Let's walk through the process step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Open the Appwrite Console
&lt;/h3&gt;

&lt;p&gt;Log in to your Appwrite Console. In the left sidebar, you'll see a section labeled &lt;strong&gt;Sites&lt;/strong&gt;. Click on it. This will take you to the Sites dashboard, where you can manage existing sites or deploy a new one.&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Create Site&lt;/strong&gt; button to get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqeopwt3m2gq0law49x59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqeopwt3m2gq0law49x59.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you have two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clone a template&lt;/strong&gt; , If you're starting fresh, this is a quick way to scaffold a new site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect a repository&lt;/strong&gt; , If you already have a working app in GitHub, this is what you'll want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose &lt;strong&gt;Connect a repository&lt;/strong&gt;. Appwrite will walk you through selecting a GitHub repository and giving the necessary permissions if you haven't already.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Configure your deployment settings
&lt;/h3&gt;

&lt;p&gt;Once your repository is connected, you'll land on the deployment configuration page. Here's what you'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: A name for your site, usually taken from your repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch&lt;/strong&gt;: The branch you want to use for production (typically &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root directory&lt;/strong&gt;: Leave this as &lt;code&gt;./&lt;/code&gt; unless your app lives in a subfolder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent mode&lt;/strong&gt;: This prevents Appwrite from adding GitHub comments when changes are pushed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework&lt;/strong&gt;: Optional, but recommended. Selecting your framework here helps Appwrite apply sensible defaults and display SSR instructions specific to your setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, scroll down to the &lt;strong&gt;Build settings&lt;/strong&gt; section. This is where you define how your app gets built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install command&lt;/strong&gt;: The default &lt;code&gt;npm install&lt;/code&gt; usually works unless your app uses a different package manager or custom setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build command&lt;/strong&gt;: For most frameworks, this is &lt;code&gt;npm run build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output directory&lt;/strong&gt;: For Next.js, this would typically be &lt;code&gt;./.next&lt;/code&gt;. Different frameworks may use different output paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your app needs environment variables, like API keys, secrets, or runtime flags, you can define them in the &lt;strong&gt;Environment variables&lt;/strong&gt; section. You can also import them from an existing &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;When you're done, click &lt;strong&gt;Deploy&lt;/strong&gt;. Appwrite will pull your code, run your build steps, and deploy your site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework-specific SSR tips
&lt;/h2&gt;

&lt;p&gt;While Appwrite Sites supports SSR, not every framework behaves the same out of the box. If your app was previously deployed on Vercel, there's a good chance it was configured with a Vercel-specific adapter, especially if you used Next.js or SvelteKit.&lt;/p&gt;

&lt;p&gt;These adapters are tailored for Vercel's environment and won't run properly on Appwrite, which expects Node.js as the runtime. To make SSR work on Appwrite, you'll need to switch to the appropriate Node.js adapter.&lt;/p&gt;

&lt;p&gt;Let's go through a few popular frameworks and what to look out for:&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js
&lt;/h3&gt;

&lt;p&gt;If you're using Next.js, SSR is supported. In your &lt;code&gt;next.config.js&lt;/code&gt; file, &lt;strong&gt;make sure you do not set the &lt;code&gt;output&lt;/code&gt; field&lt;/strong&gt;. That's specific to Vercel and can interfere with the way Appwrite handles the build output.&lt;/p&gt;

&lt;p&gt;Just let Next.js use its default behavior, and in your site settings, keep the output directory as &lt;code&gt;./.next&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SvelteKit
&lt;/h3&gt;

&lt;p&gt;SvelteKit sites hosted on Vercel typically use &lt;code&gt;@sveltejs/adapter-vercel&lt;/code&gt;. That won't work on Appwrite. To fix this, open your &lt;code&gt;svelte.config.js&lt;/code&gt; file and switch to the Node.js adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/adapter-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's set, rebuild and redeploy your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt
&lt;/h3&gt;

&lt;p&gt;Nuxt works quite seamlessly on Appwrite. In your site settings, make sure the build command is set to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SSR is supported out of the box with no additional adapter configuration needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular (with SSR)
&lt;/h3&gt;

&lt;p&gt;If you've enabled SSR in your Angular app, make sure your &lt;code&gt;src/server.ts&lt;/code&gt; file is using the &lt;code&gt;@angular/ssr/node&lt;/code&gt; package. This enables Angular Universal to run properly in a Node.js environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Astro
&lt;/h3&gt;

&lt;p&gt;For Astro apps, you'll want to install and configure the Node adapter. In &lt;code&gt;astro.config.mjs&lt;/code&gt;, update your adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@astrojs/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Astro to render pages server-side using Node.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remix
&lt;/h3&gt;

&lt;p&gt;Remix apps should be configured to use &lt;code&gt;@remix-run/node&lt;/code&gt; in the server entry file. Make sure your &lt;code&gt;entry.server.tsx&lt;/code&gt; file imports from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRequestHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@remix-run/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the server runtime is correctly set for Node environments like Appwrite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analog (Angular meta-framework)
&lt;/h3&gt;

&lt;p&gt;Analog supports SSR via Vite. To enable it, set the &lt;code&gt;ssr&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; inside your &lt;code&gt;vite.config.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;analog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This activates server-side rendering in your build pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check or change framework instructions
&lt;/h2&gt;

&lt;p&gt;If you're not sure what to do for your specific framework, you can find help directly in the Appwrite Console.&lt;/p&gt;

&lt;p&gt;Just open your deployed site from the Sites dashboard, click on &lt;strong&gt;Settings&lt;/strong&gt;, and scroll down to the &lt;strong&gt;Build settings&lt;/strong&gt; section. When you select a framework from the dropdown, Appwrite will show instructions for SSR configuration, specific to your chosen stack.&lt;/p&gt;

&lt;p&gt;That way, you'll know exactly what needs to change, and how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Hosting SSR apps with Appwrite Sites gives you a lot of flexibility. You get a Git-powered workflow, server runtime support, and integration with frameworks you already use. But more importantly, you're in control. You're not locked into a proprietary environment, and you can configure the exact build behavior you need.&lt;/p&gt;

&lt;p&gt;If you're switching from Vercel, just remember to revisit your framework's adapter and build setup. Most of the time, it's just a matter of switching to a Node.js adapter and updating a couple of config files.&lt;/p&gt;

&lt;p&gt;Once you've set that up, Appwrite Sites takes care of the rest, from cloning your repo to deploying server-rendered content.&lt;/p&gt;

&lt;p&gt;Try it out, and let us know how it works for your stack.ed to be generated dynamically on the server for personalization or real-time data. This process is called Server-Side Rendering (SSR), and Appwrite Sites supports SSR, just like it supports Client-Side Rendering (CSR) and Static Site Generation (SSG).&lt;/p&gt;

&lt;p&gt;If you've used platforms like Vercel before, this will feel familiar. You can connect your GitHub repository, choose a branch, and Appwrite will build your app and deploy it to a server.&lt;/p&gt;

&lt;p&gt;In this post, we'll show you exactly how to host an SSR-capable web app using Appwrite Sites, from repository connection to framework-specific configurations. Whether you're migrating from Vercel or starting from scratch, this guide will walk you through every step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SSR, and why does it matter?
&lt;/h2&gt;

&lt;p&gt;Server-Side Rendering (SSR) means your web app's pages are rendered on the server at request time. Unlike pre-rendered static pages, SSR allows your app to respond to each request with dynamic content that's fully rendered before it reaches the browser. It's a powerful approach for apps that need authentication, personalization, real-time data, or SEO-friendly dynamic content.&lt;/p&gt;

&lt;p&gt;Appwrite Sites supports SSR by allowing you to configure your framework's build settings and output behavior, and by running your app on a server runtime (Node.js) where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting an SSR app on Appwrite Sites
&lt;/h2&gt;

&lt;p&gt;Let's walk through the process step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Open the Appwrite Console
&lt;/h3&gt;

&lt;p&gt;Log in to your Appwrite Console. In the left sidebar, you'll see a section labeled &lt;strong&gt;Sites&lt;/strong&gt;. Click on it. This will take you to the Sites dashboard, where you can manage existing sites or deploy a new one.&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Create Site&lt;/strong&gt; button to get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Screenshot 2025-05-13 at 14.13.57.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you have two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clone a template&lt;/strong&gt; , If you're starting fresh, this is a quick way to scaffold a new site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect a repository&lt;/strong&gt; , If you already have a working app in GitHub, this is what you'll want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose &lt;strong&gt;Connect a repository&lt;/strong&gt;. Appwrite will walk you through selecting a GitHub repository and giving the necessary permissions if you haven't already.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Configure your deployment settings
&lt;/h3&gt;

&lt;p&gt;Once your repository is connected, you'll land on the deployment configuration page. Here's what you'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: A name for your site, usually taken from your repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch&lt;/strong&gt;: The branch you want to use for production (typically &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root directory&lt;/strong&gt;: Leave this as &lt;code&gt;./&lt;/code&gt; unless your app lives in a subfolder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent mode&lt;/strong&gt;: This prevents Appwrite from adding GitHub comments when changes are pushed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework&lt;/strong&gt;: Optional, but recommended. Selecting your framework here helps Appwrite apply sensible defaults and display SSR instructions specific to your setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, scroll down to the &lt;strong&gt;Build settings&lt;/strong&gt; section. This is where you define how your app gets built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install command&lt;/strong&gt;: The default &lt;code&gt;npm install&lt;/code&gt; usually works unless your app uses a different package manager or custom setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build command&lt;/strong&gt;: For most frameworks, this is &lt;code&gt;npm run build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output directory&lt;/strong&gt;: For Next.js, this would typically be &lt;code&gt;./.next&lt;/code&gt;. Different frameworks may use different output paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your app needs environment variables, like API keys, secrets, or runtime flags, you can define them in the &lt;strong&gt;Environment variables&lt;/strong&gt; section. You can also import them from an existing &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;When you're done, click &lt;strong&gt;Deploy&lt;/strong&gt;. Appwrite will pull your code, run your build steps, and deploy your site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework-specific SSR tips
&lt;/h2&gt;

&lt;p&gt;While Appwrite Sites supports SSR, not every framework behaves the same out of the box. If your app was previously deployed on Vercel, there's a good chance it was configured with a Vercel-specific adapter, especially if you used Next.js or SvelteKit.&lt;/p&gt;

&lt;p&gt;These adapters are tailored for Vercel's environment and won't run properly on Appwrite, which expects Node.js as the runtime. To make SSR work on Appwrite, you'll need to switch to the appropriate Node.js adapter.&lt;/p&gt;

&lt;p&gt;Let's go through a few popular frameworks and what to look out for:&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js
&lt;/h3&gt;

&lt;p&gt;If you're using Next.js, SSR is supported. In your &lt;code&gt;next.config.js&lt;/code&gt; file, &lt;strong&gt;make sure you do not set the &lt;code&gt;output&lt;/code&gt; field&lt;/strong&gt;. That's specific to Vercel and can interfere with the way Appwrite handles the build output.&lt;/p&gt;

&lt;p&gt;Just let Next.js use its default behavior, and in your site settings, keep the output directory as &lt;code&gt;./.next&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SvelteKit
&lt;/h3&gt;

&lt;p&gt;SvelteKit sites hosted on Vercel typically use &lt;code&gt;@sveltejs/adapter-vercel&lt;/code&gt;. That won't work on Appwrite. To fix this, open your &lt;code&gt;svelte.config.js&lt;/code&gt; file and switch to the Node.js adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/adapter-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's set, rebuild and redeploy your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt
&lt;/h3&gt;

&lt;p&gt;Nuxt works quite seamlessly on Appwrite. In your site settings, make sure the build command is set to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SSR is supported out of the box with no additional adapter configuration needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular (with SSR)
&lt;/h3&gt;

&lt;p&gt;If you've enabled SSR in your Angular app, make sure your &lt;code&gt;src/server.ts&lt;/code&gt; file is using the &lt;code&gt;@angular/ssr/node&lt;/code&gt; package. This enables Angular Universal to run properly in a Node.js environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Astro
&lt;/h3&gt;

&lt;p&gt;For Astro apps, you'll want to install and configure the Node adapter. In &lt;code&gt;astro.config.mjs&lt;/code&gt;, update your adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@astrojs/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Astro to render pages server-side using Node.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remix
&lt;/h3&gt;

&lt;p&gt;Remix apps should be configured to use &lt;code&gt;@remix-run/node&lt;/code&gt; in the server entry file. Make sure your &lt;code&gt;entry.server.tsx&lt;/code&gt; file imports from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRequestHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@remix-run/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the server runtime is correctly set for Node environments like Appwrite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analog (Angular meta-framework)
&lt;/h3&gt;

&lt;p&gt;Analog supports SSR via Vite. To enable it, set the &lt;code&gt;ssr&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; inside your &lt;code&gt;vite.config.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;analog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This activates server-side rendering in your build pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check or change framework instructions
&lt;/h2&gt;

&lt;p&gt;If you're not sure what to do for your specific framework, you can find help directly in the Appwrite Console.&lt;/p&gt;

&lt;p&gt;Just open your deployed site from the Sites dashboard, click on &lt;strong&gt;Settings&lt;/strong&gt;, and scroll down to the &lt;strong&gt;Build settings&lt;/strong&gt; section. When you select a framework from the dropdown, Appwrite will show instructions for SSR configuration, specific to your chosen stack.&lt;/p&gt;

&lt;p&gt;That way, you'll know exactly what needs to change, and how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Hosting SSR apps with Appwrite Sites gives you a lot of flexibility. You get a Git-powered workflow, server runtime support, and integration with frameworks you already use. But more importantly, you're in control. You're not locked into a proprietary environment, and you can configure the exact build behavior you need.&lt;/p&gt;

&lt;p&gt;If you're switching from Vercel, just remember to revisit your framework's adapter and build setup. Most of the time, it's just a matter of switching to a Node.js adapter and updating a couple of config files.&lt;/p&gt;

&lt;p&gt;Once you've set that up, Appwrite Sites takes care of the rest, from cloning your repo to deploying server-rendered content.&lt;/p&gt;

&lt;p&gt;Try it out, and let us know how it works for your stack.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Appwrite Sites vs Vercel: Choosing the right web hosting platform</title>
      <dc:creator>Ebenezer Don</dc:creator>
      <pubDate>Tue, 20 May 2025 13:33:57 +0000</pubDate>
      <link>https://forem.com/appwrite/appwrite-sites-vs-vercel-choosing-the-right-web-hosting-platform-3llh</link>
      <guid>https://forem.com/appwrite/appwrite-sites-vs-vercel-choosing-the-right-web-hosting-platform-3llh</guid>
      <description>&lt;p&gt;Deploying modern web applications should be fast, flexible, and reliable. As developers, we've come to expect instant previews, custom domain support, seamless environment configuration, automatic HTTPS, and the ability to deploy everything from static pages to full server-rendered apps.&lt;/p&gt;

&lt;p&gt;Vercel has been a default choice for frontend teams building with Next.js. But with the launch of &lt;strong&gt;Appwrite Sites&lt;/strong&gt;, you now have a new, integrated way to deploy web apps, especially when you want your front end to live alongside your backend, database, authentication, and storage.&lt;/p&gt;

&lt;p&gt;In this post, we'll take a look at how Appwrite Sites compares to Vercel. We'll explore everything from framework support to deployment workflows, logging, performance, and how each platform fits into a larger developer workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Appwrite Sites?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Appwrite Sites&lt;/strong&gt; is Appwrite's new deployment and hosting platform, designed to support both &lt;strong&gt;static&lt;/strong&gt; (including single-page applications) and &lt;strong&gt;server-side rendered (SSR)&lt;/strong&gt; web applications. It's tightly integrated into the Appwrite ecosystem, so if you're already using Appwrite for authentication, database, storage, or functions, you can now deploy your front end in the same place, with automatic access to shared environment variables and services.&lt;/p&gt;

&lt;p&gt;Whether you're building with Vite, Next.js, Nuxt, SvelteKit, Astro, or something simpler like Vanilla JS or even Flutter Web and &lt;a href="https://appwrite.io/blog/post/bytedance-lynx-vs-react-native" rel="noopener noreferrer"&gt;Lynx&lt;/a&gt;, Appwrite Sites provides a unified deployment workflow for both static and dynamic applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrated, full-stack hosting with Sites
&lt;/h2&gt;

&lt;p&gt;One of the biggest differences between Appwrite Sites and Vercel is how they fit into your application architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vercel&lt;/strong&gt; focuses primarily on frontend deployment. It excels at handling static assets and serverless-rendered content, especially from Next.js. It also supports other frontend frameworks like Astro, SvelteKit, Nuxt, and Remix, although it's deeply optimized for Next.js and includes native support for features like ISR (Incremental Static Regeneration) and Edge Middleware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Appwrite Sites&lt;/strong&gt;, on the other hand, is part of a &lt;strong&gt;complete development platform&lt;/strong&gt;. You're not just deploying your frontend. You're deploying it in the same environment that already knows about your database collections, users, sessions, cloud functions, storage buckets, and APIs. That means the same platform handles everything from user auth to file uploads to server-side logic, and your frontend can interact with it all without any manual configuration.&lt;/p&gt;

&lt;p&gt;This level of integration also means less risk of misconfiguration when connecting your services. Your environment variables, domain rules, CORS policies, and secrets are all managed within one project scope, reducing the friction between your frontend and backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment workflows
&lt;/h2&gt;

&lt;p&gt;Both platforms support Git-based workflows, which means you can deploy by connecting a GitHub repo and pushing changes to a selected branch. Each deployment also generates &lt;strong&gt;automatic screenshots&lt;/strong&gt;, giving you a quick visual snapshot of the deployed result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying on Vercel
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You connect your GitHub, GitLab, or Bitbucket repo.&lt;/li&gt;
&lt;li&gt;Vercel auto-detects your framework and sets up sensible defaults.&lt;/li&gt;
&lt;li&gt;Every push to your production branch triggers a build and deployment.&lt;/li&gt;
&lt;li&gt;Pull requests automatically create preview deployments with unique URLs.&lt;/li&gt;
&lt;li&gt;Each deployment includes a UI to inspect build logs, preview the deployment and view associated metadata.&lt;/li&gt;
&lt;li&gt;You can redeploy any previous commit and view full deployment history.&lt;/li&gt;
&lt;li&gt;There's no manual UI deployment support, although, there’s a CLI option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deploying on Appwrite Sites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You connect a GitHub repo to your Appwrite project.&lt;/li&gt;
&lt;li&gt;Appwrite auto-detects your framework and applies default build, install, and output settings.&lt;/li&gt;
&lt;li&gt;You choose a production branch.&lt;/li&gt;
&lt;li&gt;Each commit triggers a build and deploy.&lt;/li&gt;
&lt;li&gt;You can preview pull requests, commits, and even branches, each with their own URLs.&lt;/li&gt;
&lt;li&gt;Manual deployment is supported, with a simple drag-and-drop interface in the Console. This lets you deploy without needing Git or the CLi.&lt;/li&gt;
&lt;li&gt;Rollbacks are instant. You can restore a previous deployment with one click.&lt;/li&gt;
&lt;li&gt;Deployment output is available as a downloadable folder you can inspect locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manual deployment with Appwrite Sites offers an extra layer of flexibility, especially for small and simple static sites, which makes it easy to get started or quickly publish content without relying on Git or command-line tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework support
&lt;/h2&gt;

&lt;p&gt;Vercel is best known for its deep Next.js integration, but it also supports other frameworks like Astro, SvelteKit, Nuxt, Angular, and Remix. However, its serverless and edge rendering infrastructure is most optimized for Next.js. Features like API Routes, Middleware, and ISR work out of the box with Next.js and require extra configuration or aren't supported at the same level with other frameworks.&lt;/p&gt;

&lt;p&gt;Appwrite Sites offers &lt;strong&gt;SSR and static support for a wide range of frameworks&lt;/strong&gt;, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nuxt&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SvelteKit&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Astro&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remix&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter Web&lt;/strong&gt; (static)&lt;/li&gt;
&lt;li&gt;Lynx&lt;/li&gt;
&lt;li&gt;Analog&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JS&lt;/strong&gt; and other static site generators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each framework comes with its own build recommendations, and Appwrite Sites allows you to customize build and install commands, as well as define the output directory for compatibility. &lt;/p&gt;

&lt;p&gt;Any static framework works well with Appwrite out of the box. For popular tools like Next.js, Nuxt, and SvelteKit, Appwrite offers presets that auto-configure your build and output settings. If your framework isn’t listed, you can choose “Other” and manually set the commands and output directory.&lt;/p&gt;

&lt;p&gt;Most static and SPA setups work seamlessly. The only exception is SSR support for certain metaframeworks like Lit, which aren’t yet supported in SSR mode, but they still work fine as static sites.&lt;/p&gt;

&lt;p&gt;If you're using a framework outside of Next.js, Appwrite Sites provides a more consistent experience across the board. This is also an advantage for teams that use different frameworks for different parts of their stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting options: Static vs SSR
&lt;/h2&gt;

&lt;p&gt;Appwrite Sites supports both &lt;strong&gt;Static/SPA&lt;/strong&gt; hosting and &lt;strong&gt;Server-Side Rendering (SSR)&lt;/strong&gt;, much like Vercel. But there are a few differences in how they operate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static hosting
&lt;/h3&gt;

&lt;p&gt;On both platforms, static content is pre-rendered at build time and served via a CDN. This gives you fast cold starts and simple deploys. Appwrite Sites provides build-time environment variables and supports any static framework or tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-side rendering
&lt;/h3&gt;

&lt;p&gt;With SSR, both platforms render pages on demand.&lt;/p&gt;

&lt;p&gt;Vercel runs SSR via serverless functions or edge functions depending on your configuration and framework. Its default serverless runtime supports dynamic SSR, and Next.js projects get special handling for API routes, dynamic rendering modes, and edge cache rules.&lt;/p&gt;

&lt;p&gt;Appwrite Sites runs SSR apps in &lt;strong&gt;isolated containers&lt;/strong&gt;, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You get full runtime access to environment variables&lt;/li&gt;
&lt;li&gt;Console output from server-side code is captured in logs&lt;/li&gt;
&lt;li&gt;The SSR runtime can access Appwrite services directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That container-based model gives you more flexibility, especially if you're doing server-side API calls, interacting with Appwrite's SDK, or running custom logic during rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables
&lt;/h2&gt;

&lt;p&gt;Both platforms offer strong environment variable support, with scope control and secrets handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment variables on Vercel
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You define environment variables per environment: Development, Preview, and Production.&lt;/li&gt;
&lt;li&gt;You can override variables per branch.&lt;/li&gt;
&lt;li&gt;Secrets are encrypted and only available at build or runtime (depending on the variable).&lt;/li&gt;
&lt;li&gt;You can manage them from the dashboard or CLI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Environment variables on Appwrite Sites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You define project-wide and site-specific variables.&lt;/li&gt;
&lt;li&gt;Variables can be exposed at build time, runtime, or both.&lt;/li&gt;
&lt;li&gt;Appwrite injects &lt;strong&gt;built-in environment variables&lt;/strong&gt; for your site, project, region, version, framework, and more.&lt;/li&gt;
&lt;li&gt;You can define &lt;strong&gt;secret&lt;/strong&gt; variables that are hidden after creation and not exposed via Console or API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These built-in variables make it much easier to integrate your front end with the rest of your Appwrite services. You don't have to manually pass your API endpoint or project ID because it's already available.&lt;/p&gt;

&lt;p&gt;Appwrite also provides a &lt;strong&gt;dynamic API key automatically&lt;/strong&gt;, scoped and injected for both the build process and runtime (for SSR). This makes it easier to create or configure collections at build time, or securely perform server-to-server operations during SSR. If you were deploying on Vercel, you’d need to manually generate an Appwrite API key, store it as a secret, and rotate it regularly to maintain security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domains, CORS, and routing
&lt;/h2&gt;

&lt;p&gt;Both Vercel and Appwrite Sites allow you to connect custom domains and use automatically generated subdomains for previews.&lt;/p&gt;

&lt;p&gt;Vercel provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-generated domains per project and deployment.&lt;/li&gt;
&lt;li&gt;Custom domain support with DNS configuration.&lt;/li&gt;
&lt;li&gt;Wildcard and branch subdomains.&lt;/li&gt;
&lt;li&gt;HTTPS with automatic renewal via Let's Encrypt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appwrite Sites offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-generated domain.&lt;/li&gt;
&lt;li&gt;Custom domain support via CNAME records or full &lt;strong&gt;nameserver (NS) configuration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Branch and commit-specific URLs.&lt;/li&gt;
&lt;li&gt;HTTPS enforcement and TLS certificates out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you host both frontend and backend on Appwrite, your domain is trusted automatically. This eliminates the need to manually add frontend origins to your CORS settings because Appwrite already knows your Sites deployment is part of your project. This simplifies development and removes a common pain point: CORS errors.&lt;/p&gt;

&lt;p&gt;It’s also important for preview deployments. Vercel assigns preview URLs under a shared namespace (e.g. *.vercel.app). If you try to allow previews with a wildcard like *.vercel.app, you’re not just allowing your previews, you’re allowing every Vercel preview domain to access your backend. That introduces unnecessary risk. Appwrite avoids this entirely. Since previews are scoped to your project, they’re trusted automatically, giving you tighter control without needing to expose your backend to external domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging and monitoring
&lt;/h2&gt;

&lt;p&gt;Both platforms offer ways to monitor your applications and track issues in production, with some key differences in their approaches.&lt;/p&gt;

&lt;p&gt;Vercel provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build logs and deployment history.&lt;/li&gt;
&lt;li&gt;Function execution logs (for serverless and edge functions).&lt;/li&gt;
&lt;li&gt;Analytics for traffic and performance (on paid plans).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appwrite Sites includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request logs&lt;/strong&gt;: status codes, duration, methods, headers, paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Console output&lt;/strong&gt;: SSR logs from &lt;code&gt;console.log()&lt;/code&gt; and &lt;code&gt;console.error()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log retention&lt;/strong&gt;: 24 hours on the free plan, up to 7 days on Pro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional log disabling&lt;/strong&gt;: useful for privacy and performance-sensitive SSR routes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These logs give you immediate visibility into how your app behaves in production and will help with troubleshooting issues when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance and timeouts
&lt;/h2&gt;

&lt;p&gt;Vercel uses edge functions and CDN caching for content delivery. Static content is served from edge locations, while serverless functions run in regional data centers. Performance varies by plan tier and deployment type.&lt;/p&gt;

&lt;p&gt;Appwrite Sites uses a global CDN for static content, and container-based SSR for dynamic apps. You can configure timeouts (up to 30 seconds per request), and performance depends on your framework and hosting mode. Static hosting delivers near-instant responses through CDN caching, while SSR requires container initialization on cold starts but provides consistent performance afterward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security and isolation
&lt;/h2&gt;

&lt;p&gt;Both platforms enforce HTTPS and protect secret environment variables.&lt;/p&gt;

&lt;p&gt;Appwrite Sites also ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container isolation per deployment&lt;/li&gt;
&lt;li&gt;TLS enforcement for all domains&lt;/li&gt;
&lt;li&gt;Secret environment variables hidden after creation&lt;/li&gt;
&lt;li&gt;Preview deployments can be restricted to team members&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is important for deploying apps that handle sensitive data or use server-side logic tied to specific users or accounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to choose Appwrite Sites
&lt;/h2&gt;

&lt;p&gt;If you're already building your backend with Appwrite, or want a single platform for your full-stack app, Appwrite Sites is a natural fit. You get integrated deployments, native access to your backend, and support for a wider range of frameworks with both static and SSR modes.&lt;/p&gt;

&lt;p&gt;It's also a good choice if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need SSR for frameworks beyond Next.js&lt;/li&gt;
&lt;li&gt;Want to deploy front ends tightly coupled to backend services&lt;/li&gt;
&lt;li&gt;Prefer to manage authentication, database, storage, and hosting in one place&lt;/li&gt;
&lt;li&gt;Want rollback support, deployment visibility, and runtime logs built-in&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Appwrite Sites vs Vercel: feature comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Appwrite Sites&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Vercel&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full-stack integration&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static hosting&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side rendering&lt;/td&gt;
&lt;td&gt;Yes (container-based)&lt;/td&gt;
&lt;td&gt;Yes (serverless/edge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git-based deployment&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual deployment via UI&lt;/td&gt;
&lt;td&gt;Yes (drag-and-drop)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview deployments&lt;/td&gt;
&lt;td&gt;Branch, commit, PR&lt;/td&gt;
&lt;td&gt;Branch, commit, PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollbacks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS with Appwrite backend&lt;/td&gt;
&lt;td&gt;Automatic (trusted by default)&lt;/td&gt;
&lt;td&gt;Manual setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API key injection&lt;/td&gt;
&lt;td&gt;Automatic (build + runtime)&lt;/td&gt;
&lt;td&gt;Manual setup + rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment variables&lt;/td&gt;
&lt;td&gt;Build + runtime, auto-injected Appwrite vars&lt;/td&gt;
&lt;td&gt;Build + runtime, manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wide framework support&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Templates&lt;/td&gt;
&lt;td&gt;Yes (multi-framework)&lt;/td&gt;
&lt;td&gt;Yes (mostly Next.js)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeout configuration&lt;/td&gt;
&lt;td&gt;Yes (up to 30s)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logging&lt;/td&gt;
&lt;td&gt;Build logs, request logs, SSR console output&lt;/td&gt;
&lt;td&gt;Build + function logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom domains&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Both Appwrite Sites and Vercel are great platforms for deploying modern web applications. But they're built for slightly different workflows.&lt;/p&gt;

&lt;p&gt;Vercel is an excellent frontend-focused host, especially for teams that are all-in on Next.js, or for static sites that don’t need a backend. Appwrite Sites, meanwhile, offers a deeply integrated full-stack environment, where your front end, backend, and services all live in the same project.&lt;/p&gt;

&lt;p&gt;If you want to simplify your stack and keep everything in one place, from database to auth to hosting, Appwrite Sites offers a compelling alternative that brings clarity and flexibility to full-stack development.&lt;/p&gt;

&lt;p&gt;You can get started today by heading to your Appwrite Console and creating a new Site. Appwrite Sites has templates, GitHub integrations, and framework guides ready to go.&lt;/p&gt;

&lt;p&gt;If you have any questions, reach out to the Appwrite community on &lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; or use the &lt;a href="https://appwrite.io/contact-us" rel="noopener noreferrer"&gt;contact form&lt;/a&gt; on the website.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>vercel</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Appwrite Sites vs Netlify: Choosing the right web hosting platform</title>
      <dc:creator>Ebenezer Don</dc:creator>
      <pubDate>Tue, 20 May 2025 13:33:25 +0000</pubDate>
      <link>https://forem.com/appwrite/appwrite-sites-vs-netlify-choosing-the-right-web-hosting-platform-1ac3</link>
      <guid>https://forem.com/appwrite/appwrite-sites-vs-netlify-choosing-the-right-web-hosting-platform-1ac3</guid>
      <description>&lt;p&gt;Deploying frontend applications has gotten easier over the past decade, but also more complex behind the scenes. Most apps today need more than just HTML, CSS, and a CDN. They need authentication, secure APIs, environment configs, storage access, and sometimes server-side rendering.&lt;/p&gt;

&lt;p&gt;Netlify helped kick off a modern approach to hosting, especially for static sites and JAMstack-style architectures. But if you're building an app that also depends on a backend, managing that split becomes a real part of your workflow.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Appwrite Sites&lt;/strong&gt;, you get an alternative that treats frontend deployment as part of a full-stack environment. Instead of connecting your frontend to a separate backend via API tokens and CORS rules, Sites lives in the same platform as your database, storage, authentication, and functions.&lt;/p&gt;

&lt;p&gt;In this article, we'll break down how &lt;strong&gt;Appwrite Sites&lt;/strong&gt; and &lt;strong&gt;Netlify&lt;/strong&gt; compare, from framework support and SSR, to environment variables, deployment flows, and the developer experience of hosting modern apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Appwrite Sites?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Appwrite Sites&lt;/strong&gt; is a deployment and hosting platform within the Appwrite ecosystem. It supports both &lt;strong&gt;static sites&lt;/strong&gt; and &lt;strong&gt;server-side rendered applications&lt;/strong&gt;, with built-in Git integration, preview deployments, custom domain support, and container-based SSR.&lt;/p&gt;

&lt;p&gt;Because it's part of the same platform as Appwrite's backend services, like auth, database, storage, and cloud functions, you don't need to stitch together separate providers or manage secrets manually. Your frontend and backend live in the same project, with a shared security model and automatically scoped environment variables.&lt;/p&gt;

&lt;p&gt;Sites supports a wide range of frameworks, from Next.js and Nuxt to Astro, SvelteKit, Angular, Remix, and Flutter Web. For static apps, you can deploy via Git or manually upload a &lt;code&gt;.tar.gz&lt;/code&gt;. For SSR, Sites runs your app in a container with runtime access to secrets and Appwrite SDKs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Netlify and the JAMstack model
&lt;/h2&gt;

&lt;p&gt;Netlify pioneered the JAMstack movement, where apps are decoupled into static frontends + serverless functions + external APIs. That model works especially well for sites that are mostly static, with light dynamic behavior: marketing pages, documentation, or e-commerce frontends backed by third-party services.&lt;/p&gt;

&lt;p&gt;Netlify offers automatic builds from Git, preview URLs, branch-based environments, edge functions, form handling, and even built-in identity support (though limited in scope). It also includes a CLI and plugin ecosystem for customizing builds.&lt;/p&gt;

&lt;p&gt;But while it's flexible, it's not tightly integrated. You still need to bring your own database, authentication, file storage, and backend logic, and manage how your frontend connects to all of it.&lt;/p&gt;

&lt;p&gt;If you're building a simple frontend, Netlify is fast and effective. But for applications where frontend and backend logic are deeply connected, managing those boundaries becomes the challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Netlify
&lt;/h3&gt;

&lt;p&gt;Netlify uses Git-based deployment as its primary model. You connect your GitHub, GitLab, or Bitbucket repository, and Netlify auto-detects your framework. Every push to a branch triggers a build, with a unique deployment URL.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Branch-based previews are automatically generated&lt;/li&gt;
&lt;li&gt;Build settings can be customized via the UI or &lt;code&gt;netlify.toml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Environment variables can be scoped to Production, Preview, and Dev&lt;/li&gt;
&lt;li&gt;Rollbacks are supported&lt;/li&gt;
&lt;li&gt;There's no drag-and-drop UI deployment option, manual deploys must go through the CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Netlify does provide build plugins, custom functions, and API routing, but you'll need to wire those up separately if you're using a custom backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appwrite Sites
&lt;/h3&gt;

&lt;p&gt;Appwrite Sites also supports Git-based deployment with preview environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You connect a GitHub repo to your Appwrite project&lt;/li&gt;
&lt;li&gt;Framework detection sets defaults for build, install, and output&lt;/li&gt;
&lt;li&gt;Pushes to the production branch deploy automatically&lt;/li&gt;
&lt;li&gt;Every commit, branch, or pull request generates a unique URL for preview&lt;/li&gt;
&lt;li&gt;All builds include downloadable artifacts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual deployments&lt;/strong&gt; are supported via &lt;code&gt;.tar.gz&lt;/code&gt; or drag-and-drop in the Appwrite Console&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rollbacks are instant and available through the UI. Because the deployment lives inside your Appwrite project, it inherits access to your backend services automatically, without needing to configure tokens, keys, or external origins.&lt;/p&gt;

&lt;p&gt;This is especially helpful for teams working in mixed Git workflows, or solo developers who want a quick manual deploy option without setting up CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework support
&lt;/h2&gt;

&lt;p&gt;Netlify supports most popular frontend frameworks, including Astro, Eleventy, SvelteKit, Nuxt, Next.js, and Angular. Most are treated as static frameworks unless you configure SSR explicitly using Netlify Functions or Edge Functions.&lt;/p&gt;

&lt;p&gt;SSR support is more limited. While you can run serverless functions alongside your frontend, the integration varies depending on your framework. Next.js and Astro get the most complete support.&lt;/p&gt;

&lt;p&gt;Appwrite Sites supports a similar set of frameworks, but adds &lt;strong&gt;SSR support via containers&lt;/strong&gt;, which allows full runtime access to environment variables and Appwrite services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt; – SSR and static&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nuxt&lt;/strong&gt; – SSR and static&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SvelteKit&lt;/strong&gt; – SSR and static&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Angular&lt;/strong&gt; – SSR and static&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Astro&lt;/strong&gt; – SSR and static&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remix&lt;/strong&gt; – SSR and static&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter Web&lt;/strong&gt; – static only&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JS, Lynx, Analog, etc.&lt;/strong&gt; – static&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each framework can be customized with its own build and install commands. If your framework isn't listed, you can use “Other” and specify custom config.&lt;/p&gt;

&lt;p&gt;If you're using SSR with anything beyond Next.js or Astro, Appwrite Sites provides broader and more consistent support out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting options: Static vs SSR
&lt;/h2&gt;

&lt;p&gt;Both platforms support static and server-side rendered hosting, but their architectures differ significantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Netlify
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static&lt;/strong&gt;: Content is pre-rendered and served from a global CDN&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSR&lt;/strong&gt;: Pages are rendered using serverless or edge functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts&lt;/strong&gt;: Default timeout is 10s, up to 26s for Pro plans&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitations&lt;/strong&gt;: Memory and cold starts depend on function tier and region&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment access&lt;/strong&gt;: Functions get runtime env vars, but static content does not&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Netlify's SSR works well for lightweight APIs and dynamic content, but lacks full access to services unless you add integrations or connect to external providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appwrite Sites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static&lt;/strong&gt;: CDN-hosted HTML/CSS/JS, with build-time env vars&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSR&lt;/strong&gt;: Full server-side rendering in isolated containers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts&lt;/strong&gt;: Configurable up to 30s per request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment access&lt;/strong&gt;: Both build-time and runtime variables are supported&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt;: Console output from SSR code is captured in logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The container-based SSR model means you can use Appwrite's SDK at runtime, securely read secrets, and interact directly with databases, functions, or storage, all from your rendering logic.&lt;/p&gt;

&lt;p&gt;If your SSR routes require access to auth tokens, protected storage, or custom logic, Appwrite's model gives you more control than Netlify's function-based execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables and secrets
&lt;/h2&gt;

&lt;p&gt;Netlify uses a three-scope model, Production, Preview, Development, with env vars scoped accordingly. You define them in the dashboard or via the CLI, and they're injected at build or function runtime.&lt;/p&gt;

&lt;p&gt;Appwrite Sites provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project-wide variables shared across services&lt;/li&gt;
&lt;li&gt;Site-specific variables&lt;/li&gt;
&lt;li&gt;Secret variables (hidden after creation)&lt;/li&gt;
&lt;li&gt;Built-in Appwrite variables (project ID, endpoint, region, etc.)&lt;/li&gt;
&lt;li&gt;Automatic API key injection at build and runtime (for SSR)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can define variables once in your Appwrite project and access them across deployments, functions, and services, without needing to sync values manually.&lt;/p&gt;

&lt;p&gt;For example, instead of creating a token in Netlify and passing it to your frontend, Appwrite Sites automatically injects a scoped API key with access to your project, removing the need to manually rotate secrets or configure CORS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom domains, CORS, and trust boundaries
&lt;/h2&gt;

&lt;p&gt;Both platforms allow custom domains and HTTPS via auto-generated certificates.&lt;/p&gt;

&lt;p&gt;Netlify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports custom domains via DNS config&lt;/li&gt;
&lt;li&gt;Wildcard subdomains and previews (e.g. &lt;code&gt;.netlify.app&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Requires manual CORS configuration when connecting to external APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appwrite Sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports custom domains via CNAME or NS records&lt;/li&gt;
&lt;li&gt;Auto-generated domains for every branch and commit&lt;/li&gt;
&lt;li&gt;Built-in CORS trust if your backend is hosted on Appwrite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since Appwrite Sites and your backend live in the same project, deployed frontends are automatically recognized and trusted. You don't have to manually list frontend origins or manage preflight responses, Appwrite knows your Sites deployment is part of the same scope.&lt;/p&gt;

&lt;p&gt;This eliminates one of the most common pitfalls in multi-platform deployments: CORS misconfigurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging and observability
&lt;/h2&gt;

&lt;p&gt;Netlify provides basic logging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build logs for every deployment&lt;/li&gt;
&lt;li&gt;Function logs for serverless execution&lt;/li&gt;
&lt;li&gt;Analytics for traffic and latency (paid plans)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appwrite Sites offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build logs&lt;/li&gt;
&lt;li&gt;Request logs (status code, path, duration, headers)&lt;/li&gt;
&lt;li&gt;Console output for SSR apps&lt;/li&gt;
&lt;li&gt;Log retention (24h on Free, 7d on Pro)&lt;/li&gt;
&lt;li&gt;Optional log disabling (for performance-sensitive routes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appwrite's SSR logs include server-side console output, which is helpful when debugging SSR failures, auth edge cases, or unexpected rendering issues, without needing to integrate a third-party logging tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security and isolation
&lt;/h2&gt;

&lt;p&gt;Both platforms enforce HTTPS and offer secret management.&lt;/p&gt;

&lt;p&gt;Appwrite adds additional safeguards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolated containers for SSR deployments&lt;/li&gt;
&lt;li&gt;Secrets not visible after creation&lt;/li&gt;
&lt;li&gt;Automatic API key injection scoped to the current site&lt;/li&gt;
&lt;li&gt;Project-based access controls&lt;/li&gt;
&lt;li&gt;Preview deployment restrictions (e.g. team-only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since everything runs inside your Appwrite project, the surface area for misconfigurations is smaller. You're not exposing separate public APIs or managing external API keys, access happens within a single trusted environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appwrite Sites vs Netlify: feature comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Appwrite Sites&lt;/th&gt;
&lt;th&gt;Netlify&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Static hosting&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side rendering&lt;/td&gt;
&lt;td&gt;✅ (containers)&lt;/td&gt;
&lt;td&gt;✅ (functions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git-based deployment&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual deployment (UI)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview deployments&lt;/td&gt;
&lt;td&gt;✅ (branch, PR, commit)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom domains&lt;/td&gt;
&lt;td&gt;✅ (CNAME + NS)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment variables&lt;/td&gt;
&lt;td&gt;✅ (build + runtime, project-wide)&lt;/td&gt;
&lt;td&gt;✅ (scoped by env)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets support&lt;/td&gt;
&lt;td&gt;✅ (Option to hide after creation)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic API key injection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth, DB, storage integration&lt;/td&gt;
&lt;td&gt;✅ (native)&lt;/td&gt;
&lt;td&gt;❌ (external required)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR console logs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS for Appwrite backend&lt;/td&gt;
&lt;td&gt;✅ (auto-trusted)&lt;/td&gt;
&lt;td&gt;❌ (manual config)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeout configuration&lt;/td&gt;
&lt;td&gt;✅ (up to 30s, self-configurable)&lt;/td&gt;
&lt;td&gt;✅ (10s default, requires support team on paid plans)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Netlify is an excellent platform for static frontends and lightweight JAMstack sites. If you're building a marketing page, blog, or frontend that only talks to third-party APIs, it still delivers a clean and fast workflow.&lt;/p&gt;

&lt;p&gt;But if your application needs more than that, auth flows, custom APIs, server-side logic, secure data access, etc., &lt;strong&gt;Appwrite Sites&lt;/strong&gt; provides an integrated alternative. Instead of wiring together services across platforms, you keep your frontend and backend in one place, with fewer moving parts and tighter defaults.&lt;/p&gt;

&lt;p&gt;Appwrite Sites is built for teams that want their frontends to do more, and for developers who want full control without unnecessary complexity.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>netlify</category>
    </item>
    <item>
      <title>How to optimize your Appwrite project for cost and performance</title>
      <dc:creator>Ebenezer Don</dc:creator>
      <pubDate>Mon, 23 Sep 2024 09:02:42 +0000</pubDate>
      <link>https://forem.com/appwrite/how-to-optimize-your-appwrite-project-for-cost-and-performance-5g2g</link>
      <guid>https://forem.com/appwrite/how-to-optimize-your-appwrite-project-for-cost-and-performance-5g2g</guid>
      <description>&lt;p&gt;As your Appwrite project scales, performance and resource management become critical, not just to keep your app running smoothly, but also to avoid unexpected usage spikes. While Appwrite is designed to scale effortlessly, it's important to proactively optimize your usage so you don't reach resource limits prematurely. Effective optimization helps reduce costs, improves performance, and enhances user experience without compromising on functionality.&lt;/p&gt;

&lt;p&gt;This guide provides a detailed overview of techniques to optimize your Appwrite project, covering API request management, caching strategies, file compression, image optimization, and other methods to ensure your app performs well while staying within your desired resource limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Reducing API requests: Smart querying and consolidation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every API request consumes resources, and when requests are made inefficiently, they can consume substantial resources and increase usage costs. Here are strategies to help reduce unnecessary API calls:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Efficient use of &lt;code&gt;listDocuments&lt;/code&gt; with queries&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In Appwrite, fetching multiple documents from a database is made easy with the &lt;a href="https://appwrite.io/docs/references/cloud/client-web/databases#listDocuments" rel="noopener noreferrer"&gt;listDocuments&lt;/a&gt; method. This method allows you to retrieve all documents in a collection or apply filters using the Query API. Instead of making multiple requests for each document, you can fetch only the relevant data with a single request.&lt;/p&gt;

&lt;p&gt;For example, in a content management system where you need to load blog posts written by a particular author, rather than making individual requests for each document, use Appwrite's &lt;code&gt;listDocuments&lt;/code&gt; method with a filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;DATABASE_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;COLLECTION_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Michael Scott&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By fetching all the documents you need in one go and applying filters, you reduce the number of requests and improve performance. However, as we'll see in the next section, you should use the &lt;code&gt;listDocuments&lt;/code&gt; method carefully to avoid fetching unnecessary data, else you might end up with a large dataset that could slow down your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Optimize pagination and filtering&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For applications with large datasets (e.g., e-commerce platforms with thousands of products), retrieving all data at once can overwhelm your system. Use Appwrite’s pagination and filtering feature to only fetch what’s immediately needed.&lt;/p&gt;

&lt;p&gt;For example, if you’re loading products from a database, instead of fetching all products, fetch them in batches using pagination.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;DATABASE_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;COLLECTION_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Meredith Palmer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="c1"&gt;// Fetch the first 20 records&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secondPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;DATABASE_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;COLLECTION_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JaneDoe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="c1"&gt;// Fetch the next 20 records&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This strategy will not only conserve bandwidth but will ensure that your queries return faster results, improving your user experience.&lt;/p&gt;

&lt;p&gt;For more information on querying documents, the &lt;a href="https://appwrite.io/docs/products/databases/queries" rel="noopener noreferrer"&gt;Appwrite Queries documentation&lt;/a&gt; provides detailed examples and options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Utilizing Appwrite’s realtime API for data updates
&lt;/h3&gt;

&lt;p&gt;When building real-time applications (e.g., chat apps or collaborative tools), polling APIs frequently can result in unnecessary usage and increased server load. Appwrite’s &lt;a href="https://appwrite.io/docs/apis/realtime" rel="noopener noreferrer"&gt;Realtime API&lt;/a&gt; solves this by allowing you to subscribe to events and receive updates in real time via WebSockets. This ensures that your app remains responsive without the need for constant polling.&lt;/p&gt;

&lt;p&gt;For example, you can subscribe to file upload events in real-time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;files&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buckets.*.files.*.create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New file uploaded:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to handling real-time updates, Appwrite's Realtime API can help decide when further requests are needed. Instead of continuously fetching data to check for updates, you can create a versioning system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Versioning Document&lt;/strong&gt;: Create a document with a single column, &lt;code&gt;version&lt;/code&gt;, to track updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscribe to Changes&lt;/strong&gt;: Use the Realtime API to monitor changes in this document. If the &lt;code&gt;version&lt;/code&gt; field updates, it signals that the data has changed and needs re-fetching.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Appwrite’s Realtime API supports multiple channels, such as &lt;code&gt;files&lt;/code&gt;, &lt;code&gt;account&lt;/code&gt;, and specific &lt;code&gt;collections&lt;/code&gt;, ensuring updates from any part of your app. To learn more about the Realtime API, refer to the &lt;a href="https://appwrite.io/docs/realtime" rel="noopener noreferrer"&gt;Appwrite Realtime documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By using Appwrite's real-time feature, you drastically reduce API request overhead, especially for high-traffic apps like live dashboards or messaging platforms, while maintaining instant, event-driven updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Effective caching: Reducing redundant data fetching&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Caching is one of the most important strategies for improving both performance and resource management in your Appwrite project. By caching frequently accessed data, you reduce the number of redundant requests sent to your Appwrite instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Client-side caching with localStorage or IndexedDB&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For non-sensitive or rarely changing data, client-side caching can significantly reduce server load and improve application responsiveness. Use the browser’s &lt;code&gt;localStorage&lt;/code&gt; or &lt;code&gt;IndexedDB&lt;/code&gt; to store data that users frequently access, such as user settings, app configurations, or product lists.&lt;/p&gt;

&lt;p&gt;For instance, in a to-do list app, user preferences (e.g., preferred task view) can be cached locally so that the app doesn’t need to retrieve this data from Appwrite on every page load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cache user preferences in localStorage&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userPreferences&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieve user preferences from cache&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedPreferences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userPreferences&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces unnecessary API requests and allows for instant access to cached data, improving performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Optimized cache expiry and invalidations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Caching data on the client side is effective, but it must be combined with intelligent cache expiry strategies to avoid serving stale data. Ensure that the cache is invalidated and refreshed when necessary, such as when the data changes or after a certain time period.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cache with expiration (using localStorage)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveToCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Cache for 1 hour&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getFromCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cachedItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Invalidate stale cachereturn null&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures your users get up-to-date data while reducing the number of requests made to the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Server-side caching with Redis&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Redis is a widely-used, high-performance in-memory data store that can be an excellent choice for server-side caching in your Appwrite projects. Redis can be deployed alongside your Appwrite backend to cache frequently accessed data, reducing the load on your Appwrite instance and speeding up response times for users.&lt;/p&gt;

&lt;p&gt;For example, in an e-commerce application, you could cache product categories, prices, or frequently queried data in Redis. This way, instead of hitting the database for every request, your application can retrieve data directly from Redis, which significantly improves performance for repeated requests. You can learn more about Redis in the &lt;a href="https://redis.io/documentation" rel="noopener noreferrer"&gt;Redis documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Optimizing file storage: Compression and efficient file delivery&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Managing large files can be a significant source of resource consumption. Optimizing file storage and delivery can help keep storage costs down and ensure faster data transfers.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Bucket compression&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;One of the most important optimizations for file storage is &lt;strong&gt;bucket compression&lt;/strong&gt;. Appwrite allows you to compress files in your buckets using either the &lt;code&gt;gzip&lt;/code&gt; or &lt;code&gt;zstd&lt;/code&gt; compression algorithms. Enabling compression reduces the file size and conserves storage space, which is particularly useful for large files and media-heavy apps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gzip&lt;/strong&gt; is a widely-used compression algorithm that offers good compression ratios for many types of files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zstd&lt;/strong&gt; (Zstandard) is a modern, high-performance compression algorithm that provides better compression efficiency and decompression speed compared to gzip, making it a great choice for high-performance applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enable compression for a bucket, you can set this up via the Appwrite Console or programmatically using the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bucketId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bucketName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;compression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zstd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that files larger than &lt;strong&gt;20MB&lt;/strong&gt; are not compressed, even if compression is enabled. This is done to prevent performance bottlenecks when handling large files. Enabling compression at the bucket level not only helps reduce storage usage but also speeds up file transfers by reducing the amount of data sent over the network.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Optimizing image delivery with the Preview API&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Appwrite allows you to serve compressed and optimized versions of your images to reduce bandwidth usage and improve performance. You can use the preview endpoint to adjust image quality, resolution, format, and more, without needing to modify the original file. This is useful for serving responsive images on the web, where you might want to reduce file sizes for faster load times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Serve an optimized image preview&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optimizedImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFilePreview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bucketId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The bucket ID where the file is stored&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fileId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// The file ID of the uploaded image&lt;/span&gt;
  &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// Resize the width to 800px&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// Keep the original height (aspect ratio preserved)&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// Crop the image centered if cropping is needed&lt;/span&gt;
  &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// Set image quality to 80%&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// No border&lt;/span&gt;
  &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// No border color&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// No border radius&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// Full opacity&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// No rotation&lt;/span&gt;
  &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// No background color&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Convert the image to WebP format for better compression&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this example shows how to serve an optimized image preview, and will greatly improve load times, it will not affect the original file size in your storage. So if you want to save storage space, consider compressing and optimizing files at the time of upload. A good practice for image optimization is to use formats like &lt;code&gt;WebP&lt;/code&gt;, which offer better compression than JPEG or PNG.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing file delivery with CDNs and regional project deployment
&lt;/h3&gt;

&lt;p&gt;For improved file delivery performance, especially in media-heavy applications, you can leverage a domain-level CDN like &lt;strong&gt;Cloudflare&lt;/strong&gt;. A CDN caches files and serves them from locations closer to your users, reducing load times and improving the overall experience without overburdening your Appwrite server.&lt;/p&gt;

&lt;p&gt;In addition, deploying your Appwrite project in a region near your user base can further reduce latency. Currently, Appwrite supports the &lt;strong&gt;FRA (Frankfurt) region&lt;/strong&gt;, which is great for users in Europe. We're also expanding to more regions soon, giving you even more options to optimize performance based on your audience's location.&lt;/p&gt;

&lt;p&gt;By combining CDNs and regional project deployments, you can enhance file delivery speeds, reduce latency, and ensure a more responsive user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Using serverless functions for optimized workflows&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Serverless functions in Appwrite are a powerful tool for optimizing resource usage. Instead of handling complex, resource-heavy operations on the client or in your core backend, offload these tasks to serverless functions that can execute asynchronously and on-demand.&lt;/p&gt;

&lt;p&gt;Tasks like generating reports, processing data, or transforming files can be offloaded to serverless functions. This approach frees up the client and backend from performing expensive computations and ensures that heavy workloads don’t slow down your core application.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. Setting up usage limits, alerts, and budget controls&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Proactively managing your resource usage in Appwrite is key to avoiding unexpected overages and optimizing costs. Appwrite offers built-in tools for setting up usage alerts and budget controls to help developers manage their consumption.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Budget controls&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can also enable budget alerts to monitor your spending and prevent unexpected charges. For teams managing larger projects or multiple clients, setting budget limits ensures you stay within financial expectations.&lt;/p&gt;

&lt;p&gt;To configure budget alerts, start by navigating to the &lt;strong&gt;Appwrite Cloud Console&lt;/strong&gt;, then go to the &lt;strong&gt;Organisation&lt;/strong&gt; section and select &lt;strong&gt;Billing&lt;/strong&gt;. Here, you’ll find options to manage your budget. You can set a &lt;strong&gt;budget cap&lt;/strong&gt; to define a hard limit on your spending, and in the &lt;strong&gt;Budget Alerts&lt;/strong&gt; section, you can enable notifications that trigger when your spending reaches a certain threshold. This ensures you are alerted before exceeding your desired budget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjdoznhtl82frkl0cffk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjdoznhtl82frkl0cffk.png" alt="Budget controls in Appwrite Cloud Console" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;6. Monitoring and scaling your Appwrite project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Appwrite handles scalability efficiently, particularly in its cloud environment. Appwrite Cloud automatically scales resources as needed, ensuring that your application can handle increased traffic or workloads without requiring manual intervention. This automatic scaling allows you to focus on building your app, while Appwrite dynamically adjusts the resources behind the scenes to maintain optimal performance during traffic spikes.&lt;/p&gt;

&lt;p&gt;While this is a significant advantage of using Appwrite Cloud, self-hosted instances also provide flexibility for custom scaling configurations. By monitoring your Appwrite project’s resource usage, you can identify bottlenecks, optimize your app, and scale horizontally as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Automatic scaling in Appwrite&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Appwrite's infrastructure is built on top of Docker, which allows for containerized scaling. Each service in Appwrite is containerized, meaning services like databases, storage, or functions can be scaled horizontally as demand increases. This happens automatically in the cloud version of Appwrite, making it easier for developers to handle surges in user traffic without experiencing downtime or performance degradation. For self-hosted Appwrite, scaling is also possible but requires setting up and managing Docker containers manually.&lt;/p&gt;

&lt;p&gt;In Appwrite’s cloud environment, you don’t have to worry about manually configuring load balancers or managing server instances to scale your application. Appwrite automatically distributes workloads, ensuring smooth operation regardless of traffic volumes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Monitoring resource usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Appwrite provides built-in monitoring to help track API usage, database operations, storage, and other key metrics. This monitoring allows you to identify potential inefficiencies, such as high API request volumes or unnecessary data fetches, before they escalate into larger issues. While Appwrite handles automatic scaling, regular monitoring can help you optimize your application to avoid overuse of resources and prevent unnecessary costs.&lt;/p&gt;

&lt;p&gt;You can monitor your Appwrite project's performance via the dashboard, which gives insights into your API request count, database operations, and storage usage. This data helps you manage your plan limits more effectively and optimize your app to avoid unexpected scaling needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wv9t12mc97mur9esj8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wv9t12mc97mur9esj8j.png" alt="Monitoring resource usage in Appwrite dashboard" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Horizontal scaling&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For self-hosted environments, Appwrite can be scaled horizontally by replicating containers across multiple servers. Stateless containers like those running functions or workers can be easily replicated to distribute workloads. However, for stateful services like databases, manual scaling configurations may be required.&lt;/p&gt;

&lt;p&gt;Horizontal scaling ensures that the load is distributed evenly across multiple instances, making your application more resilient during high-traffic periods.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Optimizing your Appwrite project ensures you not only provide a better experience to your users but also prevent unnecessary resource overuse. By applying the techniques discussed in this guide, you can keep your project running smoothly while staying within your plan limits.&lt;/p&gt;

&lt;p&gt;These optimizations aren’t just about cost savings—they are about making your app more scalable, efficient, and reliable as it grows. Rather than waiting until you hit plan limits, taking a proactive approach builds trust and ensures your users always experience the best possible performance, even as your app scales.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>backend</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
