[{"data":1,"prerenderedAt":256},["ShallowReactive",2],{"$fi_SA3l8D9e4tuLzFLMXUroEj8Vi4FUp0B2g2TbBke08":3,"post-nuxt-3-supabase-mistakes-i-made":147},{"site":4,"features":8,"stripe":10,"bridalfile":12,"navigation":13,"branding":124,"footer":127},{"id":5,"name":6,"domain":7},"7578a1b2-a8ec-462f-8980-d46ebefc76a2","Pwa Developer","pwadeveloper.uk",{"products":9,"bookings":9,"event_capacity":9,"ugc":9},false,{"enabled":9,"test_mode":11},true,{"enabled":9},{"footer":14,"header":42,"services":67},{"id":15,"name":16,"items":17},"4c83a83d-7d89-442d-8e4c-717e61d71c19","Footer Navigation",[18,22,26,30,34,38],{"id":19,"url":20,"label":21},"b8c9d0e1-f2a3-4b4c-5d6e-7f8a9b0c1d2e","/about","About",{"id":23,"url":24,"label":25},"c9d0e1f2-a3b4-4c5d-6e7f-8a9b0c1d2e3f","/blog","Blog",{"id":27,"url":28,"label":29},"d0e1f2a3-b4c5-4d6e-7f8a-9b0c1d2e3f4a","/contact","Contact",{"id":31,"url":32,"label":33},"e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b","/websites","Websites",{"id":35,"url":36,"label":37},"d1e2f3a4-1111-4a2b-8c3d-dddd11112222","/services/nuxt","Nuxt",{"id":39,"url":40,"label":41},"d2e3f4a5-2222-4b3c-9d4e-dddd22223333","/services/supabase","Supabase",{"id":43,"name":44,"items":45},"090e7007-6dd0-4416-8ce2-2680c446d2a9","Main Navigation",[46,48,52,56,58,60,62],{"id":47,"url":20,"label":21},"c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f",{"id":49,"url":50,"label":51},"a43446fd-355b-474a-a846-6f02ba7b4f68","/services","Services",{"id":53,"url":54,"label":55},"6b5e66d9-5267-4948-86b9-11ef75fcf821","/how-i-build","How I Build",{"id":57,"url":32,"label":33},"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",{"id":59,"url":24,"label":25},"d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a",{"id":61,"url":28,"label":29},"f6a7b8c9-d0e1-4f2a-3b4c-5d6e7f8a9b0c",{"id":63,"url":64,"label":65,"target":66},"e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b","https://www.youtube.com/@anothermagentodev9161","YouTube","_blank",{"id":68,"name":69,"items":70},"9a2b3c4d-9999-4a2b-8c3d-aaaabbbbcccc","Services Menu",[71,77,83,89,95,101,107,113,119],{"id":72,"url":73,"icon":74,"label":75,"description":76},"1a2b3c4d-1111-4a2b-8c3d-111122223333","/services/pwa","fa-solid fa-mobile-screen-button","PWA","Installable, offline-first apps",{"id":78,"url":79,"icon":80,"label":81,"description":82},"2b3c4d5e-2222-4b3c-9d4e-222233334444","/services/wordpress","fa-brands fa-wordpress","WordPress","Themes, plugins, rescue work",{"id":84,"url":85,"icon":86,"label":87,"description":88},"3c4d5e6f-3333-4c4d-8e5f-333344445555","/services/magento","fa-solid fa-cart-shopping","Magento","Ecommerce & platform work",{"id":90,"url":91,"icon":92,"label":93,"description":94},"4d5e6f70-4444-4d5e-9f60-444455556666","/services/vue","fa-brands fa-vuejs","Vue & Nuxt","Reactive frontends, SSR apps",{"id":96,"url":97,"icon":98,"label":99,"description":100},"708192a3-7777-4081-8293-777788889999","/services/headless-cms","fa-solid fa-cube","Headless","Structured content APIs",{"id":102,"url":103,"icon":104,"label":105,"description":106},"8192a3b4-8888-4192-93a4-88889999aaaa","/services/ai-consultancy","fa-solid fa-robot","AI Consultancy","Where AI actually helps",{"id":108,"url":109,"icon":110,"label":111,"description":112},"a1b2c3d4-1234-4a2b-8c3d-aaaa11112222","/services/migrations","fa-solid fa-arrow-right-arrow-left","Migrations","Move platforms, keep your SEO",{"id":114,"url":115,"icon":116,"label":117,"description":118},"b2c3d4e5-2345-4b3c-9d4e-bbbb22223333","/services/technical-seo","fa-solid fa-gauge-high","Technical SEO & Performance","Core Web Vitals & speed",{"id":120,"url":32,"icon":121,"label":122,"description":123},"c3d4e5f6-3456-4c4d-8e5f-cccc33334444","fa-solid fa-globe","Custom Websites","Bespoke sites, not templates",{"logo":125,"logoDark":125,"favicon":125,"tagline":126},null,"WordPress & Web Developer in Hull, East Yorkshire",{"summary":128,"copyright":125,"address":129,"contact":133,"socialLinks":134,"openingHours":146,"logos":125},"Senior freelance web developer in Hull, East Yorkshire. 15+ years building fast, custom websites and web apps in WordPress, Magento, Vue and Nuxt. Work directly with the developer.",{"line1":125,"line2":125,"city":130,"state":131,"postalCode":125,"country":132},"Hull","East Yorkshire","United Kingdom",{"phone":125,"email":125},[135,138,142],{"url":64,"icon":136,"platform":137},"fa-brands fa-youtube","youtube",{"url":139,"icon":140,"platform":141},"https://github.com/adamcjackson1982","fa-brands fa-github","github",{"url":143,"icon":144,"platform":145},"https://www.linkedin.com/in/adamcjackson/","fa-brands fa-linkedin","linkedin",[],{"id":148,"slug":149,"title":150,"excerpt":151,"content":152,"content_format":250,"featured_image":251,"published":11,"published_at":252,"meta_title":253,"meta_description":254,"fields":255},"3df43e9a-ad62-4eac-b681-d29b604d37ee","nuxt-3-supabase-mistakes-i-made","Nuxt 3 and Supabase: The Mistakes I Made So You Don't Have To","Nuxt 3 and Supabase is my default stack, but I learned a few things the hard way. Here are the mistakes worth skipping, from leaked keys to connection limits.",{"type":153,"content":154},"doc",[155,161,168,172,177,181,186,190,195,199,204,208,213,217,222,226],{"type":156,"content":157},"paragraph",[158],{"text":159,"type":160},"Nuxt 3 and Supabase is my default stack. I reach for it on most new projects because it lets one person build and ship a real application without wiring up five separate services first. I still rate it. But I did not get there smoothly. A few of the lessons cost me evenings I would like back, so here are the mistakes I made, in the hope you can skip them.","text",{"type":162,"attrs":163,"content":165},"heading",{"level":164},2,[166],{"text":167,"type":160},"I leaked the service role key",{"type":156,"content":169},[170],{"text":171,"type":160},"Supabase gives you two keys: a public anon key that is safe in the browser, and a service role key that bypasses all your security rules. Early on I used the service role key in a composable to make a query work, forgetting that anything in a Nuxt component ends up in the client bundle. That key should never leave the server. These days I keep it in a private runtime config value and only ever touch it inside a server route or an API handler. If you take one thing from this post, take that: the service role key lives on the server, full stop.",{"type":162,"attrs":173,"content":174},{"level":164},[175],{"text":176,"type":160},"I forgot row level security is off until you turn it on",{"type":156,"content":178},[179],{"text":180,"type":160},"A new Supabase table has no row level security. That means if the anon key can reach it, anyone can read and write the whole table. It worked perfectly in testing, which is exactly the trap, because in testing I was the only user. Now the first thing I do after creating any table is enable row level security and write the policies, even on a table I think is private. Test it by hitting the table with the anon key and confirming you get back only what you should. Assume nothing is protected until you have proven it is.",{"type":162,"attrs":182,"content":183},{"level":164},[184],{"text":185,"type":160},"I hammered the connection pool from serverless",{"type":156,"content":187},[188],{"text":189,"type":160},"When I deploy Nuxt to a serverless host, every request can spin up a fresh function, and every function that opens its own database connection eats into a pool that is smaller than you think. The first time a client's site got a bit of traffic, things started timing out for no obvious reason. The fix was to use Supabase's pooled connection string for the server side work rather than a direct connection, and to stop opening a new client on every single request. If you are going serverless, understand your connection limits before launch, not during your first busy afternoon.",{"type":162,"attrs":191,"content":192},{"level":164},[193],{"text":194,"type":160},"I treated realtime as free",{"type":156,"content":196},[197],{"text":198,"type":160},"Supabase realtime is lovely. Subscribe to a table, get live updates, no WebSocket server to run. So I sprinkled subscriptions everywhere, including on pages that did not need live data at all. Concurrent realtime connections are capped by your tier, and I was burning through them for features nobody was using. Now I only subscribe where a user genuinely benefits from seeing changes as they happen, and I make sure every subscription is cleaned up when the component unmounts. An orphaned subscription that never closes is a slow leak you will not notice until it bites.",{"type":162,"attrs":200,"content":201},{"level":164},[202],{"text":203,"type":160},"I put auth checks in the wrong place",{"type":156,"content":205},[206],{"text":207,"type":160},"Because Nuxt renders on the server, an auth check written as if it only runs in the browser will behave in ways you do not expect. I had redirects that flickered, and protected pages that flashed their content for a moment before bouncing a logged-out visitor. The answer was to lean on the official Supabase module for Nuxt and do the auth check in server-side middleware, so the decision is made before any protected content is ever sent. If a page needs a login, the check belongs on the server, not in an onMounted hook.",{"type":162,"attrs":209,"content":210},{"level":164},[211],{"text":212,"type":160},"I left database migrations too late",{"type":156,"content":214},[215],{"text":216,"type":160},"For the first few weeks of a project I changed the database straight from the Supabase dashboard, clicking columns into existence. It felt quick. Then I needed to set up a second environment and had no reliable record of how the database got to its current shape. Rebuilding it by memory was miserable. Now I keep schema changes as migration files from day one, so the database can be recreated anywhere from a clean checkout. It is five minutes of discipline early that saves you a lost afternoon later.",{"type":162,"attrs":218,"content":219},{"level":164},[220],{"text":221,"type":160},"What I would tell my past self",{"type":156,"content":223},[224],{"text":225,"type":160},"None of these are reasons to avoid the stack. They are the normal cost of learning any set of tools well enough to trust it with real client work. The short version is this: keep the service role key on the server, turn on row level security before you write a line of app code, respect your connection and realtime limits, do auth on the server, and write migrations from the start. Get those right and Nuxt 3 with Supabase genuinely does let a small team move fast.",{"type":156,"content":227},[228,230,235,237,241,243,248],{"text":229,"type":160},"If you are weighing up this stack for a project, or you have inherited one that is misbehaving, that is the sort of thing I help Hull and East Yorkshire businesses with every week. You can read how I use ",{"text":37,"type":160,"marks":231},[232],{"type":233,"attrs":234},"link",{"href":36},{"text":236,"type":160}," and ",{"text":41,"type":160,"marks":238},[239],{"type":233,"attrs":240},{"href":40},{"text":242,"type":160}," on client work, or book a free 30-minute surgery through my ",{"text":244,"type":160,"marks":245},"contact page",[246],{"type":233,"attrs":247},{"href":28},{"text":249,"type":160}," and we can talk through where you are stuck.","tiptap","","2026-07-16T08:00:00+00:00","Nuxt 3 and Supabase: Mistakes I Made","The Nuxt 3 and Supabase mistakes I made so you don't have to: leaked service keys, row level security, connection pools, realtime limits, and migrations.",{},1784188827453]