[{"data":1,"prerenderedAt":325},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-how-close-to-the-user-should-your-code-be-i18n-slugs":134,"language-blog-slug-en-how-close-to-the-user-should-your-code-be":141},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135,138],{"locale":136,"value":137},"en","how-close-to-the-user-should-your-code-be",{"locale":139,"value":140},"nl","hoe-dichtbij-de-gebruiker-moet-jouw-code-draaien",{"page":142},{"slug":137,"i18nSlugs":143,"social":146,"title":148,"subtitle":79,"isArchived":151,"headerIllustration":152,"date":157,"authors":158,"introTitle":167,"items":168,"pivots":245,"relatedBlogPosts":257,"tags":276,"onMountedScript":161,"onUnmountedScript":161},[144,145],{"locale":136,"value":137},{"locale":139,"value":140},{"title":147,"description":148,"image":149},"Serverless & edge compute","How close to the user should your code be?",{"url":150},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761816932-jasper-blog.jpg",false,{"url":153,"alt":154,"width":155,"height":156},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761815991-2025-10-30_jasper-blog-transparent.png",null,554,451,"2025-10-30T10:07:10.411+01:00",[159],{"name":160,"lastName":161,"slug":162,"image":163},"Jasper","","jasper",{"url":164,"alt":154,"width":165,"height":166},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535518-jasper.jpg",1892,2523,"As front-end developers, we’re used to thinking about what our code does. But increasingly, where it runs is just as important. Serverless and edge computing give us new options for putting logic closer to our users, but choosing the right location isn’t always obvious.",[169,173,177,181,190,193,197,202,205,209,213,216,220,223,226,232,235,241],{"__typename":170,"id":171,"title":161,"body":172},"TextSectionRecord","TpOqyy8JSDSYglySN1M3mA","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Should you personalise content at the edge? Can you run serverless functions for everything? When is a plain CDN enough? And when do you still need a good old-fashioned server?\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">In this post, I&rsquo;ll break down how to choose where different parts of your application should run and how to factor in performance, scalability and vendor lock-in. I&rsquo;ll share how we at De Voorhoede help clients map features to infrastructure, and how to avoid common mistakes when adding modern tooling to existing systems.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":174,"title":175,"body":176},"XD72yeaHQ9WsmZdfcW90Og","You can’t put a supercomputer in everyone's pocket","\u003Cp>\u003Cspan style=\"font-weight: 400;\">I love modern tech, and at De Voorhoede, we enjoy pioneering with it. But in everything we build, we try to put the user first. And our users? They don&rsquo;t care what technology we chose or where our code runs. They just want a fast, smooth, and personalised experience.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">It&rsquo;s tempting to assume that the closer to the user your code runs, the faster things will feel. And in many cases, that&rsquo;s true. Reducing latency - the round-trip time from user interaction, to code execution, to UI update - can make a huge difference.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">But performance isn't just about distance. It&rsquo;s also about capability, what the hardware can actually handle once the request arrives.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">On the client-side, we have no control over the user's device. It might be a brand-new iPhone, or a 6-year-old Android with a dozen tabs open. In contrast, on the server-side, we have full control. We can choose machines with more CPU power, memory, and even GPU acceleration.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">The ideal setup, low latency and high capability, sounds great in theory. But in practice, putting powerful servers near every user just isn&rsquo;t realistic. It&rsquo;s expensive, hard to scale, and frankly, overkill for most use cases. You don&rsquo;t need a supercomputer at the edge to show someone their name.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">So when we architect an application, we&rsquo;re constantly balancing latency against capability. There&rsquo;s no one-size-fits-all answer. It depends on what each feature needs. Let&rsquo;s look at the options - and what they&rsquo;re good (and bad) at.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":178,"title":179,"body":180},"Myj5rXQAS5eQ4hsFgFDVYQ","Centralised servers: everything in one place","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Before we had edge runtimes, serverless functions, and global CDNs, most web applications simply ran on a central server. And to be fair, many still do.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">A centralised server gives you everything in one place: compute, file storage, and database access. Your back-end logic, front-end templates, static assets, and database connections all live together. Easy to reason about. Easy to control. When Node.js - a JavaScript server runtime - was introduced, centralised servers became part of our territory at De Voorhoede.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":182,"id":183,"image":184,"caption":161,"fullWidth":151,"captionPosition":189},"ImageRecord","MjNSDmm8Tvmya8yC1JotwA",{"url":185,"alt":186,"width":187,"height":188},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761813583-2025-10-20_jasper-blog-1.jpg","Users, Latency and Concurrency",1600,892,"bottom",{"__typename":170,"id":191,"title":161,"body":192},"fag8ThKmQmuWOmDjGBBC-Q","\u003Cp>\u003Cspan style=\"font-weight: 400;\">These days, containers are often used to run central servers. Tools like Docker and Kubernetes make it easier to deploy consistent environments, scale workloads, and move between cloud providers. But the architecture remains largely the same: user requests go to a central location, where everything happens.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">This model still makes sense in many situations:\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cul>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">Your users are located close to the server (for example, a Dutch company serving Dutch users).\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">Your traffic is predictable enough to size your server accordingly.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">You want full control over your runtime and environment.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">You&rsquo;re hosting an application with complex compute needs or dependencies that don&rsquo;t play well with distributed runtimes.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">But it&rsquo;s not without trade-offs:\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cul>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Latency\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">: Users far from that data centre feel it. No matter how much you optimise your code, network distance adds unavoidable delay.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Concurrency\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">: A single server has finite resources.&nbsp; Scaling for sudden traffic spikes often requires over-provisioning, or getting into more complex orchestration.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Flexibility\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> is limited: every feature has to live on the same server, or you start introducing service sprawl.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">And of course, we&rsquo;re glossing over databases here, a big topic in itself. For now, let&rsquo;s just say that central servers often sit close to the database for good reasons: low-latency access, persistent connections, and predictable performance. But that also tethers them to one location.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">In short, a central server gives you a lot of power and simplicity, but only if your application's needs, users, and traffic patterns align with that central point. Next, let&rsquo;s look at what happens when we start distributing things, first with CDNs.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003C!-- notionvc: 57f1f17a-4d92-427a-8ae8-2ac74719f19c -->\u003C\u002Fp>",{"__typename":170,"id":194,"title":195,"body":196},"aaY81KPGTOuvJa9HFErjbA","CDNs,  the first edge: static files closer to the user","\u003Cp>\u003Cspan style=\"font-weight: 400;\">CDNs were the first big step toward bringing the web closer to the user, but only for static assets. They dramatically reduce latency and offload work from origin servers, but they&rsquo;re also limited: they can&rsquo;t run logic or access data. Understanding what CDNs are good at (and not) is key for deciding where to place front-end features.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cb>What CDNs do well is straightforward: they serve static files, HTML, CSS, JavaScript, images, from servers physically closer to the user.\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> That reduces latency and bandwidth costs, and helps scale effortlessly to a global audience without spinning up more infrastructure.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":182,"id":198,"image":199,"caption":161,"fullWidth":151,"captionPosition":189},"H8LEGUjTQCy7Fi5AglvtpQ",{"url":200,"alt":186,"width":187,"height":201},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761813589-2025-10-20_jasper-blog-2.jpg",891,{"__typename":170,"id":203,"title":161,"body":204},"fbZkMWUVTwObckiaiDLyng","\u003Cp>\u003Cspan style=\"font-weight: 400;\">For us at De Voorhoede, CDNs really started to shine with the rise of the JAMstack. Pre-rendered HTML, deployed to a CDN, made sites blazingly fast and cheap to host. Thank you Netlify It also opened the door to headless architectures, separating the front-end from CMSs, commerce engines, and back-end systems. That gave us a huge advantage: we could iterate on the front-end independently. Preview environments became the norm. Instead of maintaining one acceptance and one production server, we had a fresh deploy for every pull request. It was fast, simple, and empowering.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">But CDNs can only take you so far. A CDN is essentially a server-side cache, great for performance, but not for flexibility. It requires thoughtful invalidation strategies, whether time-based (\u003C\u002Fspan>\u003Ccode>\u003Cspan style=\"font-weight: 400;\">max-age\u003C\u002Fspan>\u003C\u002Fcode>\u003Cspan style=\"font-weight: 400;\">, \u003C\u002Fspan>\u003Ccode>\u003Cspan style=\"font-weight: 400;\">stale-while-revalidate\u003C\u002Fspan>\u003C\u002Fcode>\u003Cspan style=\"font-weight: 400;\">), tag-based (like Fastly&rsquo;s Surrogate Keys or Cloudflare&rsquo;s Cache Tags), or manual purging. And ultimately, the cache is shared: it can&rsquo;t personalise, run logic, or respond to user-specific state. For anything dynamic, like authenticated content, A\u002FB testing, or per-user rendering, you either fall back to client-side workarounds or hit your origin server again.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">So how do we bring compute closer to the user?\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":206,"title":207,"body":208},"Mm2Q4yztRIaXV5ru7QwT6Q","Serverless functions – compute getting closer","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Serverless functions, like AWS Lambda or Google Cloud Functions, bring compute closer to the user. Not quite to the edge, but to regional servers (like \u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\">eu-central-1\u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\"> or \u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\">us-west-2\u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\">). So closer than centralised servers and more dynamic than a CDN.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">They&rsquo;re flexible and easy to use: just deploy a function, and it runs when needed, whether once or a million times. They scale automatically, you don&rsquo;t pay for idle time, and they&rsquo;re great for simple API integrations.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Most providers support multiple languages, including JavaScript (Node.js). That made serverless a natural fit for us at De Voorhoede. We could stay in JavaScript, write backend logic like form handlers or CMS webhooks, and deploy it right alongside the front-end.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003C!-- notionvc: 9a783e11-c034-4fe5-bc06-6644dc31472b -->\u003C\u002Fp>",{"__typename":182,"id":210,"image":211,"caption":161,"fullWidth":151,"captionPosition":189},"V9X27AESSQmq24VHLAy7pA",{"url":212,"alt":186,"width":187,"height":188},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761813598-2025-10-20_jasper-blog-4.jpg",{"__typename":170,"id":214,"title":161,"body":215},"BZe91oyqT5OLzRA_rbXbvg","\u003Cp>\u003Cspan style=\"font-weight: 400;\">But serverless has trade-offs.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cul>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Stateless by design\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">:&nbsp; each function call starts fresh, no in-memory state, no persistent connections. That&rsquo;s fine for lightweight logic, but starts to hurt as things grow.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Cold starts:\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> functions that haven&rsquo;t been used in a while take longer to respond. Cold starts can range from a few hundred milliseconds to several seconds, depending on the platform and size of your code.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Not all packages play nice:\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> while Node.js is supported, some libraries (like those with native dependencies or file system access) don&rsquo;t work well. Larger packages slow things down, try running Prisma with GraphQL and you&rsquo;ll feel it.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cb>Platform-specific function APIs:\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> each provider has its own way of handling requests and responses. Abstractions like the Serverless Framework can help, but add complexity and vendor coupling.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Serverless is a great step toward modular, scalable infrastructure. But if we want even faster response times and logic that runs \u003C\u002Fspan>\u003Ci>\u003Cspan style=\"font-weight: 400;\">right at the edge\u003C\u002Fspan>\u003C\u002Fi>\u003Cspan style=\"font-weight: 400;\">, there&rsquo;s one step closer to the user: edge functions.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":170,"id":217,"title":218,"body":219},"HHOwi0-VQ8ybnEsVQNzzRQ","Edge functions - compute at your doorstep","\u003Cp>\u003Cspan style=\"font-weight: 400;\">With edge functions, we can finally run dynamic logic as close to the user as it gets, short of running on their device. These functions execute code right where our static files already live: at global edge locations. They&rsquo;re ideal for lightweight, latency-critical tasks like authentication, A\u002FB testing, rewrites, and simple API integrations. \u003C\u002Fspan>\u003C\u002Fp>",{"__typename":182,"id":221,"image":222,"caption":161,"fullWidth":151,"captionPosition":189},"GwNWOzyfQMK2TayoFWNHYg",{"url":212,"alt":186,"width":187,"height":188},{"__typename":170,"id":224,"title":161,"body":225},"WeGxZvs1TL6eMB7G1qBztw","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Unlike serverless functions, edge functions don&rsquo;t run in full containers or VMs. Instead, they use \u003C\u002Fspan>\u003Cb>isolates\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, a lightweight, sandboxed environment built for speed and scale. They offer ultra-low latency and near-zero cold starts, but come with tight resource limits and no access to many Node.js features that typical packages depend on.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":182,"id":227,"image":228,"caption":161,"fullWidth":151,"captionPosition":189},"SAuGZMKTS2eksvBxfVSWBg",{"url":229,"alt":230,"width":187,"height":231},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761813603-2025-10-20_jasper-blog-5.jpg","Cloudflare, Deno and Bun",473,{"__typename":170,"id":233,"title":161,"body":234},"Z5MWJBV6T6itgoeq3B4oew","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Notable runtimes include \u003C\u002Fspan>\u003Cb>Cloudflare Workers\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, \u003C\u002Fspan>\u003Cb>Deno Deploy\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, and (to some extent) \u003C\u002Fspan>\u003Cb>Bun\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">. As with serverless platforms, each has its own APIs and quirks. That makes code portability a challenge. Fortunately, the \u003C\u002Fspan>\u003Cb>WinterCG\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> group is working to standardise web APIs across runtimes, so we can write portable, web-native JavaScript that works anywhere. Meanwhile, the \u003C\u002Fspan>\u003Cb>UnJS\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> community is building tiny, runtime-agnostic utilities like \u003C\u002Fspan>\u003Ccode>\u003Cspan style=\"font-weight: 400;\">unenv\u003C\u002Fspan>\u003C\u002Fcode>\u003Cspan style=\"font-weight: 400;\">, \u003C\u002Fspan>\u003Ccode>\u003Cspan style=\"font-weight: 400;\">h3\u003C\u002Fspan>\u003C\u002Fcode>\u003Cspan style=\"font-weight: 400;\">, and \u003C\u002Fspan>\u003Ccode>\u003Cspan style=\"font-weight: 400;\">unstorage\u003C\u002Fspan>\u003C\u002Fcode>\u003Cspan style=\"font-weight: 400;\">, modules designed to &ldquo;just work&rdquo; across environments.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Frameworks play a key role in completing this universal developer experience. \u003C\u002Fspan>\u003Cb>Astro\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, \u003C\u002Fspan>\u003Cb>SvelteKit\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, \u003C\u002Fspan>\u003Cb>Remix\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, and \u003C\u002Fspan>\u003Cb>Nuxt 3+\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> all offer runtime adapters that let you target edge platforms without changing your code. These adapters compile your app to match the chosen runtime, abstracting away environment-specific details while keeping the final output lean and performant. The notable exception is \u003C\u002Fspan>\u003Cb>Next.js\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\">, which, despite being open source, is deeply tied to Vercel&rsquo;s platform and difficult to run fully elsewhere.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":182,"id":236,"image":237,"caption":161,"fullWidth":151,"captionPosition":189},"Ti8vTYHRTPO4zo_6Wk3YUg",{"url":238,"alt":239,"width":187,"height":240},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1761813608-2025-10-20_jasper-blog-6.jpg","Sveltekit, Remix and Nuxt3",791,{"__typename":170,"id":242,"title":243,"body":244},"CCFEA9pYSR2mGrfMWUA_NQ","So, how close should your code be?","\u003Cp>\u003Cspan style=\"font-weight: 400;\">It turns out the answer is simple: \u003C\u002Fspan>\u003Cb>as close to the user as possible, using just enough power for the job.\u003C\u002Fb>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">In real estate, there&rsquo;s a saying: \u003C\u002Fspan>\u003Cb>location, location, location.\u003C\u002Fb>\u003Cspan style=\"font-weight: 400;\"> The same applies to your application logic. The closer you place your code to the user, the faster and more responsive your experience will feel. But that speed comes with trade-offs. Edge runtimes are fast, but limited. Serverless adds flexibility, but at a cost. Central servers give you control, but only if your users can wait for it.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Putting it all together:\u003C\u002Fspan>\u003C\u002Fp>\n\u003Ctable border=\"1\" height=\"405\" style=\"border-collapse: collapse;\">\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Criteria\u003C\u002Fstrong>\u003C\u002Ftd>\n\u003Cth>\n\u003Cp>\u003Cstrong>Static CDN\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fth>\n\u003Ctd>\u003Cstrong>Edge Function (e.g. Workers)\u003C\u002Fstrong>\u003C\u002Ftd>\n\u003Cth>\n\u003Cp>\u003Cstrong>Regional Serverless\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fth>\n\u003Cth>\n\u003Cp>\u003Cstrong>Centralised Server\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Latency (close to user)\u003C\u002Fstrong>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">⚠️ (region-based)\u003C\u002Fspan>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">❌\u003C\u002Fspan>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Concurrency (auto-scaling &amp; volume)\u003C\u002Fstrong>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">⚠️ (requires scaling infra)\u003C\u002Fspan>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\n\u003Cp>\u003Cstrong>Dynamic logic\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">❌\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\n\u003Cp>\u003Cstrong>Cold starts\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">❌\u003C\u002Fspan>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅ (near-zero)\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">❌ (can be slow)\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\n\u003Cp>\u003Cstrong>Heavy computation\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">❌\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">❌\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\n\u003Cp>\u003Cstrong>Portability (no vendor-lock)\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">⚠️ (runtime-specific)\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">⚠️ (platform-specific)\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">✅\u003C\u002Fspan>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\n\u003Cp>\u003Cstrong>Best for\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Static sites, assets\u003C\u002Fspan>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\u003Cspan style=\"font-weight: 400;\">APIs, personalised UIs, A\u002FB tests, auth\u003C\u002Fspan>\u003C\u002Ftd>\n\u003Ctd>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">APIs, light server logic\u003C\u002Fspan>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003Ctd>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Monoliths, legacy systems\u003C\u002Fspan>\u003C\u002Fp>\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">At De Voorhoede, we start by asking: \u003Cem>W\u003C\u002Fem>\u003C\u002Fspan>\u003Cem>\u003Cspan style=\"font-weight: 400;\">hat&rsquo;s the least powerful, closest option that can handle this part of the job?\u003C\u002Fspan>\u003C\u002Fem>\u003C\u002Fp>\n\u003Cul>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">If it can be static, we pre-render and cache it.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">If it needs lightweight logic, we run it at the edge.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli style=\"font-weight: 400;\" aria-level=\"1\">\u003Cspan style=\"font-weight: 400;\">Only when something needs more compute or persistent connections do we fall back to serverless or central servers.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">The modern front-end isn&rsquo;t just about what you build, but where you run it. And with today&rsquo;s tooling, we can choose with more precision than ever.\u003C\u002Fspan>\u003C\u002Fp>",[246],{"title":247,"body":161,"links":248,"mailchimpValue":161,"mailchimpName":161,"mailchimpId":161,"formType":161,"contactPerson":254},"Got a project we can work on?",[249],{"__typename":250,"id":251,"title":252,"link":253},"InternalLinkRecord","163140952","Contact us",{"__typename":38},{"name":160,"lastName":161,"jobTitle":255,"image":256},"CTO, Co-founder",{"url":164,"alt":154,"width":165,"height":166},[258,269],{"slug":259,"title":260,"date":261,"authors":262},"lessons-learned-debugging-inp"," Lessons learned debugging Interaction to Next Paint (INP)","2024-08-16T09:46:11.712+02:00",[263],{"name":264,"image":265},"Declan",{"url":266,"alt":154,"width":267,"height":268},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534636-placeholder.jpg",1235,1646,{"slug":270,"title":271,"date":272,"authors":273},"full-stack-front-end","Full-stack Front-end","2022-07-19T02:00:00.000+02:00",[274],{"name":160,"image":275},{"url":164,"alt":154,"width":165,"height":166},[277,304],{"id":278,"title":279,"slug":280,"blogPosts":281},"NJN9K2rdSY2pn9MvchHLtw","Strategy","strategy",[282,293,300],{"slug":283,"title":284,"date":285,"authors":286},"reclaiming-digital-sovereignty-on-european-infrastructure","Reclaiming Digital Sovereignty on European Infrastructure","2026-01-29T12:02:28.591+01:00",[287],{"name":288,"image":289},"Luuk",{"url":290,"alt":154,"width":291,"height":292},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1721036156-luuk-edit-edit.jpg",2198,2969,{"slug":294,"title":295,"date":296,"authors":297},"future-front-end-replaceable-inadequate-innovative","The future of front-end: replaceable, inadequate or innovative?","2022-07-18T02:00:00.000+02:00",[298],{"name":160,"image":299},{"url":164,"alt":154,"width":165,"height":166},{"slug":270,"title":271,"date":272,"authors":301},[302],{"name":160,"image":303},{"url":164,"alt":154,"width":165,"height":166},{"id":305,"title":306,"slug":307,"blogPosts":308},"b-HOCOQTRJKMsff0UxhDcg","Web performance ","web-performance",[309,313,317],{"slug":283,"title":284,"date":285,"authors":310},[311],{"name":288,"image":312},{"url":290,"alt":154,"width":291,"height":292},{"slug":259,"title":260,"date":261,"authors":314},[315],{"name":264,"image":316},{"url":266,"alt":154,"width":267,"height":268},{"slug":318,"title":319,"date":320,"authors":321},"front-end-at-the-edge","Front-end at the Edge","2022-10-04T02:00:00.000+02:00",[322],{"name":323,"image":324},"Vera",{"url":266,"alt":154,"width":267,"height":268},1776256139033]