[{"data":1,"prerenderedAt":798},["ShallowReactive",2],{"article:running-multiple-local-supabase-projects-in-parallel":3,"\u002Fblog\u002Frunning-multiple-local-supabase-projects-in-parallel-surround":787},{"id":4,"title":5,"author":6,"body":7,"date":776,"description":777,"extension":778,"image":779,"meta":780,"minRead":247,"navigation":243,"path":781,"published":243,"seo":782,"stem":783,"tags":784,"__hash__":786},"blog\u002Fblog\u002Frunning-multiple-local-supabase-projects-in-parallel.md","Running Multiple Local Supabase Projects in Parallel","Baljeet Singh",{"type":8,"value":9,"toc":766},"minimark",[10,31,38,46,51,54,61,65,68,189,204,208,215,331,353,380,384,387,418,421,450,454,461,560,566,570,573,580,583,589,594,608,611,615,618,638,698,701,705,756,759,762],[11,12,13,14,18,19,22,23,26,27,30],"p",{},"If you work on multiple projects that each use local Supabase, you've hit this wall: every project's ",[15,16,17],"code",{},"supabase start"," wants the same ports. API on ",[15,20,21],{},"54321",", database on ",[15,24,25],{},"54322",", Studio on ",[15,28,29],{},"54323"," — the CLI defaults are identical everywhere. So you can only run one stack at a time, and switching projects means stopping one stack and starting another. Every single time.",[11,32,33,34,37],{},"It gets worse if you use AI coding tools. If your MCP config points at ",[15,35,36],{},"localhost:54321"," in every repo, whichever stack happens to be running answers — so an agent working in project2 can silently run migrations against project1's database. That's not a port conflict, that's data corruption waiting to happen.",[11,39,40,41,45],{},"Here's the setup I landed on: ",[42,43,44],"strong",{},"static port blocks per project, all stacks running in parallel, permanently."," You never think about ports again, and you never restart a stack just to switch projects.",[47,48,50],"h2",{"id":49},"why-static-ports-and-not-auto-allocation","Why Static Ports (and Not Auto-Allocation)",[11,52,53],{},"My first instinct was to build a small wrapper CLI that auto-allocates free ports — like Vite does for dev servers. Don't do this.",[11,55,56,57,60],{},"Supabase ports don't stay inside the CLI the way a Vite port does. They leak into ",[15,58,59],{},".env"," files, hardcoded fallbacks in app configs, seed scripts, MCP configs, Studio bookmarks, and webhook tunnels. Dynamic allocation means all of those drift every time ports get reassigned. Static ports assigned once and committed to the repo means the number lives in git and nothing ever drifts.",[47,62,64],{"id":63},"the-port-scheme","The Port Scheme",[11,66,67],{},"Give each project a block of 10 ports, and keep the last digit meaning the same thing everywhere:",[69,70,71,90],"table",{},[72,73,74],"thead",{},[75,76,77,81,84,87],"tr",{},[78,79,80],"th",{},"Service",[78,82,83],{},"project1 (default)",[78,85,86],{},"project2",[78,88,89],{},"project3",[91,92,93,108,121,134,147,161,175],"tbody",{},[75,94,95,99,102,105],{},[96,97,98],"td",{},"shadow DB",[96,100,101],{},"54320",[96,103,104],{},"54420",[96,106,107],{},"54520",[75,109,110,113,115,118],{},[96,111,112],{},"API",[96,114,21],{},[96,116,117],{},"54421",[96,119,120],{},"54521",[75,122,123,126,128,131],{},[96,124,125],{},"DB",[96,127,25],{},[96,129,130],{},"54422",[96,132,133],{},"54522",[75,135,136,139,141,144],{},[96,137,138],{},"Studio",[96,140,29],{},[96,142,143],{},"54423",[96,145,146],{},"54523",[75,148,149,152,155,158],{},[96,150,151],{},"Mailpit",[96,153,154],{},"54324",[96,156,157],{},"54424",[96,159,160],{},"54524",[75,162,163,166,169,172],{},[96,164,165],{},"Analytics",[96,167,168],{},"54327",[96,170,171],{},"54427",[96,173,174],{},"54527",[75,176,177,180,183,186],{},[96,178,179],{},"Pooler",[96,181,182],{},"54329",[96,184,185],{},"54429",[96,187,188],{},"54529",[11,190,191,192,195,196,199,200,203],{},"Your first project keeps the CLI defaults (smallest blast radius — it probably has the most references already). Every additional project gets the next ",[15,193,194],{},"+100"," block. The last-digit convention means you always know that ",[15,197,198],{},"x2"," is a database and ",[15,201,202],{},"x3"," is a Studio, no matter which project you're in.",[47,205,207],{"id":206},"step-1-change-the-ports-in-configtoml","Step 1: Change the Ports in config.toml",[11,209,210,211,214],{},"In each project's ",[15,212,213],{},"supabase\u002Fconfig.toml",", update every port. For project2:",[216,217,222],"pre",{"className":218,"code":219,"filename":213,"language":220,"meta":221,"style":221},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[api]\nport = 54421\n\n[db]\nport = 54422\nshadow_port = 54420\n\n[db.pooler]\nport = 54429\n\n[studio]\nport = 54423\n\n[inbucket]\nport = 54424\n\n[analytics]\nport = 54427\n","toml","",[15,223,224,232,238,245,251,257,263,268,274,280,285,291,297,302,308,314,319,325],{"__ignoreMap":221},[225,226,229],"span",{"class":227,"line":228},"line",1,[225,230,231],{},"[api]\n",[225,233,235],{"class":227,"line":234},2,[225,236,237],{},"port = 54421\n",[225,239,241],{"class":227,"line":240},3,[225,242,244],{"emptyLinePlaceholder":243},true,"\n",[225,246,248],{"class":227,"line":247},4,[225,249,250],{},"[db]\n",[225,252,254],{"class":227,"line":253},5,[225,255,256],{},"port = 54422\n",[225,258,260],{"class":227,"line":259},6,[225,261,262],{},"shadow_port = 54420\n",[225,264,266],{"class":227,"line":265},7,[225,267,244],{"emptyLinePlaceholder":243},[225,269,271],{"class":227,"line":270},8,[225,272,273],{},"[db.pooler]\n",[225,275,277],{"class":227,"line":276},9,[225,278,279],{},"port = 54429\n",[225,281,283],{"class":227,"line":282},10,[225,284,244],{"emptyLinePlaceholder":243},[225,286,288],{"class":227,"line":287},11,[225,289,290],{},"[studio]\n",[225,292,294],{"class":227,"line":293},12,[225,295,296],{},"port = 54423\n",[225,298,300],{"class":227,"line":299},13,[225,301,244],{"emptyLinePlaceholder":243},[225,303,305],{"class":227,"line":304},14,[225,306,307],{},"[inbucket]\n",[225,309,311],{"class":227,"line":310},15,[225,312,313],{},"port = 54424\n",[225,315,317],{"class":227,"line":316},16,[225,318,244],{"emptyLinePlaceholder":243},[225,320,322],{"class":227,"line":321},17,[225,323,324],{},"[analytics]\n",[225,326,328],{"class":227,"line":327},18,[225,329,330],{},"port = 54427\n",[11,332,333,334,337,338,341,342,345,346,348,349,352],{},"One important thing: ",[42,335,336],{},"your data is safe."," Docker containers and volumes are namespaced by the ",[15,339,340],{},"project_id"," at the top of ",[15,343,344],{},"config.toml",", not by ports. As long as each project has a distinct ",[15,347,340],{}," (it does by default — it's set when you run ",[15,350,351],{},"supabase init","), you can change ports freely and your existing database comes back intact after a restart.",[216,354,358],{"className":355,"code":356,"language":357,"meta":221,"style":221},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","supabase stop && supabase start\n","bash",[15,359,360],{"__ignoreMap":221},[225,361,362,366,370,374,377],{"class":227,"line":228},[225,363,365],{"class":364},"sBMFI","supabase",[225,367,369],{"class":368},"sfazB"," stop",[225,371,373],{"class":372},"sMK4o"," &&",[225,375,376],{"class":364}," supabase",[225,378,379],{"class":368}," start\n",[47,381,383],{"id":382},"step-2-update-anything-that-hardcodes-the-old-ports","Step 2: Update Anything That Hardcodes the Old Ports",[11,385,386],{},"Grep each repo for the old defaults and update them:",[216,388,390],{"className":355,"code":389,"language":357,"meta":221,"style":221},"grep -rn \"5432[0-9]\" . --exclude-dir=node_modules --exclude-dir=.git\n",[15,391,392],{"__ignoreMap":221},[225,393,394,397,400,403,406,409,412,415],{"class":227,"line":228},[225,395,396],{"class":364},"grep",[225,398,399],{"class":368}," -rn",[225,401,402],{"class":372}," \"",[225,404,405],{"class":368},"5432[0-9]",[225,407,408],{"class":372},"\"",[225,410,411],{"class":368}," .",[225,413,414],{"class":368}," --exclude-dir=node_modules",[225,416,417],{"class":368}," --exclude-dir=.git\n",[11,419,420],{},"Typical suspects:",[422,423,424,438,444],"ul",{},[425,426,427,429,430,433,434,437],"li",{},[15,428,59],{}," and ",[15,431,432],{},".env.example"," files (",[15,435,436],{},"SUPABASE_URL=http:\u002F\u002F127.0.0.1:54421",")",[425,439,440,441,437],{},"Hardcoded fallbacks in app configs (",[15,442,443],{},"process.env.SUPABASE_URL ?? 'http:\u002F\u002F127.0.0.1:54421'",[425,445,446,447,437],{},"Seed scripts with direct Postgres connection strings (",[15,448,449],{},"postgresql:\u002F\u002Fpostgres:postgres@127.0.0.1:54422\u002Fpostgres",[47,451,453],{"id":452},"step-3-point-your-mcp-config-at-the-right-stack","Step 3: Point Your MCP Config at the Right Stack",[11,455,456,457,460],{},"This is the part that fixes the \"agent talks to the wrong database\" problem. The Supabase CLI serves an official MCP endpoint on the local API port — no extra MCP server needed. Commit a ",[15,458,459],{},".mcp.json"," in each repo root pointing at that project's API port:",[216,462,466],{"className":463,"code":464,"filename":459,"language":465,"meta":221,"style":221},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"mcpServers\": {\n    \"supabase\": {\n      \"type\": \"http\",\n      \"url\": \"http:\u002F\u002F127.0.0.1:54421\u002Fmcp\"\n    }\n  }\n}\n","json",[15,467,468,473,490,503,526,545,550,555],{"__ignoreMap":221},[225,469,470],{"class":227,"line":228},[225,471,472],{"class":372},"{\n",[225,474,475,478,482,484,487],{"class":227,"line":234},[225,476,477],{"class":372},"  \"",[225,479,481],{"class":480},"spNyl","mcpServers",[225,483,408],{"class":372},[225,485,486],{"class":372},":",[225,488,489],{"class":372}," {\n",[225,491,492,495,497,499,501],{"class":227,"line":240},[225,493,494],{"class":372},"    \"",[225,496,365],{"class":364},[225,498,408],{"class":372},[225,500,486],{"class":372},[225,502,489],{"class":372},[225,504,505,508,512,514,516,518,521,523],{"class":227,"line":247},[225,506,507],{"class":372},"      \"",[225,509,511],{"class":510},"sbssI","type",[225,513,408],{"class":372},[225,515,486],{"class":372},[225,517,402],{"class":372},[225,519,520],{"class":368},"http",[225,522,408],{"class":372},[225,524,525],{"class":372},",\n",[225,527,528,530,533,535,537,539,542],{"class":227,"line":253},[225,529,507],{"class":372},[225,531,532],{"class":510},"url",[225,534,408],{"class":372},[225,536,486],{"class":372},[225,538,402],{"class":372},[225,540,541],{"class":368},"http:\u002F\u002F127.0.0.1:54421\u002Fmcp",[225,543,544],{"class":372},"\"\n",[225,546,547],{"class":227,"line":259},[225,548,549],{"class":372},"    }\n",[225,551,552],{"class":227,"line":265},[225,553,554],{"class":372},"  }\n",[225,556,557],{"class":227,"line":270},[225,558,559],{"class":372},"}\n",[11,561,562,563,565],{},"Because the config is project-scoped (not global), Claude Code opened in project2 talks to project2's stack — always. Migrations, SQL, type generation, logs, all against the right database. If you had a global MCP config pointing at ",[15,564,21],{},", delete it; that's the footgun.",[47,567,569],{"id":568},"the-ram-catch","The RAM Catch",[11,571,572],{},"Here's the thing nobody warns you about: a full local Supabase stack is ~12 containers, and Docker Desktop's VM has a fixed memory budget (mine was set to just under 4 GB). When I started three stacks in parallel, the third one got OOM-killed during boot.",[11,574,575,576,579],{},"The culprit is ",[42,577,578],{},"analytics"," — the Logflare container plus its Vector log shipper eat roughly 600 MB per stack, more during boot. Everything else combined is only ~550 MB per stack.",[11,581,582],{},"Two ways out:",[11,584,585,588],{},[42,586,587],{},"Option A — raise Docker's memory."," Docker Desktop → Settings → Resources → Memory. Bump it to ~10 GB and keep everything enabled.",[11,590,591],{},[42,592,593],{},"Option B — disable analytics in the projects where you don't need it:",[216,595,597],{"className":218,"code":596,"filename":213,"language":220,"meta":221,"style":221},"[analytics]\nenabled = false\n",[15,598,599,603],{"__ignoreMap":221},[225,600,601],{"class":227,"line":228},[225,602,324],{},[225,604,605],{"class":227,"line":234},[225,606,607],{},"enabled = false\n",[11,609,610],{},"The only thing you lose is the Logs UI inside local Studio. Database, auth, storage, realtime, edge functions, and Studio itself all keep working. I kept analytics on in my main project and turned it off in the others — three stacks now idle at ~2.4 GB total.",[47,612,614],{"id":613},"leave-them-running","Leave Them Running",[11,616,617],{},"Once they're up, just leave them up. That's the whole point.",[422,619,620,626,632],{},[425,621,622,625],{},[42,623,624],{},"Idle stacks cost almost nothing in CPU."," They just sit there.",[425,627,628,631],{},[42,629,630],{},"Stopping them doesn't save disk space."," Your data lives in Docker volumes and the images are on disk either way. Stopping only frees RAM inside Docker's VM — which is reserved from your OS regardless.",[425,633,634,637],{},[42,635,636],{},"They survive until Docker stops."," After a reboot you'll need to start them again. A tiny loop handles it:",[216,639,641],{"className":355,"code":640,"language":357,"meta":221,"style":221},"for d in project1 project2 project3; do (cd ~\u002FCode\u002F$d && supabase start); done\n",[15,642,643],{"__ignoreMap":221},[225,644,645,649,653,656,659,662,665,668,671,674,678,681,684,687,689,692,695],{"class":227,"line":228},[225,646,648],{"class":647},"s7zQu","for",[225,650,652],{"class":651},"sTEyZ"," d ",[225,654,655],{"class":647},"in",[225,657,658],{"class":368}," project1",[225,660,661],{"class":368}," project2",[225,663,664],{"class":368}," project3",[225,666,667],{"class":372},";",[225,669,670],{"class":647}," do",[225,672,673],{"class":372}," (",[225,675,677],{"class":676},"s2Zo4","cd",[225,679,680],{"class":368}," ~\u002FCode\u002F",[225,682,683],{"class":651},"$d ",[225,685,686],{"class":372},"&&",[225,688,376],{"class":364},[225,690,691],{"class":368}," start",[225,693,694],{"class":372},");",[225,696,697],{"class":647}," done\n",[11,699,700],{},"One tip if you start several cold at once: do it sequentially, not in parallel. Simultaneous cold boots spike memory and can trip the CLI's health-check timeouts.",[47,702,704],{"id":703},"summary","Summary",[422,706,707,721,734,740,746,753],{},[425,708,709,710,713,714,713,717,720],{},"Each project gets a static, committed block of ports: ",[15,711,712],{},"543xx",", ",[15,715,716],{},"544xx",[15,718,719],{},"545xx",", ...",[425,722,723,724,727,728,730,731,733],{},"Last digit = same service everywhere (",[15,725,726],{},"x1"," API, ",[15,729,198],{}," DB, ",[15,732,202],{}," Studio)",[425,735,736,737,739],{},"Data is keyed to ",[15,738,340],{},", not ports — changing ports is safe",[425,741,742,743,745],{},"A per-repo ",[15,744,459],{}," pointing at that project's API port keeps AI agents on the right database",[425,747,748,749,752],{},"Disable ",[15,750,751],{},"[analytics]"," (or raise Docker's memory) so multiple stacks fit in the VM",[425,754,755],{},"Leave everything running; switching projects becomes instant",[11,757,758],{},"No wrapper CLI, no port juggling, no restarts. Just numbers that never change, committed to git.",[11,760,761],{},"Let me know if you run into any issues ✌️",[763,764,765],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":221,"searchDepth":234,"depth":234,"links":767},[768,769,770,771,772,773,774,775],{"id":49,"depth":234,"text":50},{"id":63,"depth":234,"text":64},{"id":206,"depth":234,"text":207},{"id":382,"depth":234,"text":383},{"id":452,"depth":234,"text":453},{"id":568,"depth":234,"text":569},{"id":613,"depth":234,"text":614},{"id":703,"depth":234,"text":704},"2026-08-05","How to run several local Supabase stacks side by side with the Supabase CLI — static port blocks per project, no port conflicts, no restarting stacks when you switch projects, and Claude Code always talking to the right database.","md","\u002Fimg\u002Fmultiple-supabase-projects-parallel.jpg",{},"\u002Fblog\u002Frunning-multiple-local-supabase-projects-in-parallel",{"title":5,"description":777},"blog\u002Frunning-multiple-local-supabase-projects-in-parallel",[785],"Web Development","qEyhFDOyDFCVakPpXuKeix54Jk_kcKJGPlTHMoNr7L8",[788,793],{"title":789,"path":790,"stem":791,"description":792,"children":-1},"Pixl Preview, An App For Real Time Mobile Design Previews","\u002Fblog\u002Fpixl-preview-an-app-for-real-time-mobile-design-previews-266","blog\u002Fpixl-preview-an-app-for-real-time-mobile-design-previews-266","In this article we will take a look at Pixl Preview, An App For Real Time Mobile Design Previews",{"title":794,"path":795,"stem":796,"description":797,"children":-1},"Up & Running with Vue.js 2.0 by creating a simple blog application","\u002Fblog\u002Frunning-vue-js-2-0-creating-simple-blog-application-709","blog\u002Frunning-vue-js-2-0-creating-simple-blog-application-709","In this article we will be Up & Running with Vue.js 2.0 by creating a simple blog application",1785915829612]