[{"data":1,"prerenderedAt":757},["ShallowReactive",2],{"content-query-4c458bihwS":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"layout":10,"crumb":11,"summary":12,"group":13,"order":14,"port":15,"updated":16,"cta":17,"related":25,"faq":44,"body":57,"_type":750,"_id":751,"_source":752,"_file":753,"_stem":754,"_extension":755,"sitemap":756},"/localhost/3001","localhost",false,"","localhost:3001: what runs on port 3001 and how to fix it","localhost:3001 is where Next.js and other dev servers go when 3000 is busy, plus BrowserSync UI and Uptime Kuma. Fix 'refused to connect' and free port 3001.","reference","localhost:3001","Second dev server, API next to a frontend, BrowserSync UI, Uptime Kuma.","Web frameworks",6,3001,"2026-10-28",{"eyebrow":18,"title":19,"text":20,"to":21,"label":22,"secondaryTo":23,"secondaryLabel":24},"Webhook Relay","Send webhooks to the API on 3001","When the frontend lives on 3000 and the API on 3001, webhooks belong on the API. relay forward gives it a permanent public URL and delivers every request to localhost:3001, logged and replayable. relay connect shares either port over HTTPS.","/docs/webhooks/internal/localhost/","Receive webhooks locally","/tunnels/","Explore Tunnels",[26,29,32,35,38,41],{"title":27,"to":28},"localhost:3000","/localhost/3000/",{"title":30,"to":31},"localhost:5173 (Vite)","/localhost/5173/",{"title":33,"to":34},"localhost:8081","/localhost/8081/",{"title":36,"to":37},"127.0.0.1 and the loopback address","/localhost/127-0-0-1/",{"title":39,"to":40},"What is a reverse proxy?","/glossary/reverse-proxy/",{"title":42,"to":43},"Receive webhooks on localhost","/blog/receive-webhooks-on-localhost/",[45,48,51,54],{"q":46,"a":47},"What is localhost:3001?","localhost:3001 is port 3001 on your own machine. It is usually a second dev server: Next.js and similar tools move to 3001 when 3000 is taken, and many projects run an Express or Nest API on 3001 next to a frontend on 3000. BrowserSync's control panel and Uptime Kuma also use 3001.",{"q":49,"a":50},"Why is my app on localhost:3001 instead of 3000?","Something else was already listening on port 3000, so the dev server picked the next free port. Next.js and Nuxt do this automatically and Create React App asks first. Stop the old process on 3000 if you want the app back on 3000.",{"q":52,"a":53},"Why does localhost:3001 refuse to connect?","Nothing is listening on 3001. If your app normally lands there only because 3000 is busy, it may be on 3000 now. Check the terminal for the actual URL.",{"q":55,"a":56},"How do I call an API on port 3001 from a frontend on port 3000?","The two ports are different origins, so the browser applies CORS. Either enable CORS on the API for http://localhost:3000 or configure the frontend dev server to proxy API paths to port 3001 so the browser only talks to one origin.",{"type":58,"children":59,"toc":742},"root",[60,88,95,196,202,306,312,404,437,473,479,506,578,584,634,640,645,680,692,697,731,736],{"type":61,"tag":62,"props":63,"children":64},"element","p",{},[65,78,80,86],{"type":61,"tag":66,"props":67,"children":68},"strong",{},[69,76],{"type":61,"tag":70,"props":71,"children":73},"code",{"className":72},[],[74],{"type":75,"value":11},"text",{"type":75,"value":77}," is port 3001 on your own computer, and it's usually the \"second\" dev server: the place Next.js lands when 3000 is already taken, or the API that runs beside a frontend on 3000.",{"type":75,"value":79}," BrowserSync's control panel and Uptime Kuma also default to 3001. If you see ",{"type":61,"tag":70,"props":81,"children":83},{"className":82},[],[84],{"type":75,"value":85},"ERR_CONNECTION_REFUSED",{"type":75,"value":87},", nothing is listening there right now.",{"type":61,"tag":89,"props":90,"children":92},"h2",{"id":91},"what-runs-on-port-3001",[93],{"type":75,"value":94},"What runs on port 3001",{"type":61,"tag":96,"props":97,"children":98},"table",{},[99,118],{"type":61,"tag":100,"props":101,"children":102},"thead",{},[103],{"type":61,"tag":104,"props":105,"children":106},"tr",{},[107,113],{"type":61,"tag":108,"props":109,"children":110},"th",{},[111],{"type":75,"value":112},"What",{"type":61,"tag":108,"props":114,"children":115},{},[116],{"type":75,"value":117},"Why it's on 3001",{"type":61,"tag":119,"props":120,"children":121},"tbody",{},[122,144,157,170,183],{"type":61,"tag":104,"props":123,"children":124},{},[125,131],{"type":61,"tag":126,"props":127,"children":128},"td",{},[129],{"type":75,"value":130},"Next.js, Nuxt, Remix dev server",{"type":61,"tag":126,"props":132,"children":133},{},[134,136,142],{"type":75,"value":135},"Moved automatically because ",{"type":61,"tag":137,"props":138,"children":139},"a",{"href":28},[140],{"type":75,"value":141},"3000",{"type":75,"value":143}," was busy",{"type":61,"tag":104,"props":145,"children":146},{},[147,152],{"type":61,"tag":126,"props":148,"children":149},{},[150],{"type":75,"value":151},"Create React App",{"type":61,"tag":126,"props":153,"children":154},{},[155],{"type":75,"value":156},"Asks \"Would you like to run the app on another port instead?\" and picks 3001",{"type":61,"tag":104,"props":158,"children":159},{},[160,165],{"type":61,"tag":126,"props":161,"children":162},{},[163],{"type":75,"value":164},"Express / NestJS / Fastify API",{"type":61,"tag":126,"props":166,"children":167},{},[168],{"type":75,"value":169},"Convention when the frontend owns 3000",{"type":61,"tag":104,"props":171,"children":172},{},[173,178],{"type":61,"tag":126,"props":174,"children":175},{},[176],{"type":75,"value":177},"BrowserSync UI",{"type":61,"tag":126,"props":179,"children":180},{},[181],{"type":75,"value":182},"Control panel next to the proxied site on 3000",{"type":61,"tag":104,"props":184,"children":185},{},[186,191],{"type":61,"tag":126,"props":187,"children":188},{},[189],{"type":75,"value":190},"Uptime Kuma",{"type":61,"tag":126,"props":192,"children":193},{},[194],{"type":75,"value":195},"Default port of the self-hosted monitor",{"type":61,"tag":89,"props":197,"children":199},{"id":198},"fix-localhost3001-refused-to-connect",[200],{"type":75,"value":201},"Fix \"localhost:3001 refused to connect\"",{"type":61,"tag":203,"props":204,"children":205},"ol",{},[206,225,266],{"type":61,"tag":207,"props":208,"children":209},"li",{},[210,215,217,223],{"type":61,"tag":66,"props":211,"children":212},{},[213],{"type":75,"value":214},"Check where the app actually is.",{"type":75,"value":216}," If your app only went to 3001 because 3000 was busy last time, it may be back on 3000 now. Read the ",{"type":61,"tag":70,"props":218,"children":220},{"className":219},[],[221],{"type":75,"value":222},"Local:",{"type":75,"value":224}," URL your dev server prints.",{"type":61,"tag":207,"props":226,"children":227},{},[228,233,235,241,243,249,251,257,258,264],{"type":61,"tag":66,"props":229,"children":230},{},[231],{"type":75,"value":232},"API not started.",{"type":75,"value":234}," In a monorepo, ",{"type":61,"tag":70,"props":236,"children":238},{"className":237},[],[239],{"type":75,"value":240},"npm run dev",{"type":75,"value":242}," in the frontend package won't start the API. Use your workspace runner (",{"type":61,"tag":70,"props":244,"children":246},{"className":245},[],[247],{"type":75,"value":248},"turbo dev",{"type":75,"value":250},", ",{"type":61,"tag":70,"props":252,"children":254},{"className":253},[],[255],{"type":75,"value":256},"npm run dev --workspaces",{"type":75,"value":250},{"type":61,"tag":70,"props":259,"children":261},{"className":260},[],[262],{"type":75,"value":263},"docker compose up",{"type":75,"value":265},") or start the API in its own terminal.",{"type":61,"tag":207,"props":267,"children":268},{},[269,274,276,282,284,290,292,297,299,304],{"type":61,"tag":66,"props":270,"children":271},{},[272],{"type":75,"value":273},"Docker Compose.",{"type":75,"value":275}," Each service needs its own mapping, for example ",{"type":61,"tag":70,"props":277,"children":279},{"className":278},[],[280],{"type":75,"value":281},"\"3001:3001\"",{"type":75,"value":283}," for the API. From another container, call the API by service name (",{"type":61,"tag":70,"props":285,"children":287},{"className":286},[],[288],{"type":75,"value":289},"http://api:3001",{"type":75,"value":291},"), not ",{"type":61,"tag":70,"props":293,"children":295},{"className":294},[],[296],{"type":75,"value":5},{"type":75,"value":298},". Inside a container, ",{"type":61,"tag":70,"props":300,"children":302},{"className":301},[],[303],{"type":75,"value":5},{"type":75,"value":305}," is that container.",{"type":61,"tag":89,"props":307,"children":309},{"id":308},"find-and-free-a-busy-port-3001",[310],{"type":75,"value":311},"Find and free a busy port 3001",{"type":61,"tag":313,"props":314,"children":318},"pre",{"className":315,"code":316,"language":317,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark","# macOS / Linux\nlsof -i :3000 -i :3001\nkill -9 $(lsof -ti :3001)\n","bash",[319],{"type":61,"tag":70,"props":320,"children":321},{"__ignoreMap":7},[322,334,365],{"type":61,"tag":323,"props":324,"children":327},"span",{"class":325,"line":326},"line",1,[328],{"type":61,"tag":323,"props":329,"children":331},{"style":330},"--shiki-default:#6A737D",[332],{"type":75,"value":333},"# macOS / Linux\n",{"type":61,"tag":323,"props":335,"children":337},{"class":325,"line":336},2,[338,344,350,356,360],{"type":61,"tag":323,"props":339,"children":341},{"style":340},"--shiki-default:#B392F0",[342],{"type":75,"value":343},"lsof",{"type":61,"tag":323,"props":345,"children":347},{"style":346},"--shiki-default:#79B8FF",[348],{"type":75,"value":349}," -i",{"type":61,"tag":323,"props":351,"children":353},{"style":352},"--shiki-default:#9ECBFF",[354],{"type":75,"value":355}," :3000",{"type":61,"tag":323,"props":357,"children":358},{"style":346},[359],{"type":75,"value":349},{"type":61,"tag":323,"props":361,"children":362},{"style":352},[363],{"type":75,"value":364}," :3001\n",{"type":61,"tag":323,"props":366,"children":368},{"class":325,"line":367},3,[369,374,379,385,389,394,399],{"type":61,"tag":323,"props":370,"children":371},{"style":346},[372],{"type":75,"value":373},"kill",{"type":61,"tag":323,"props":375,"children":376},{"style":346},[377],{"type":75,"value":378}," -9",{"type":61,"tag":323,"props":380,"children":382},{"style":381},"--shiki-default:#E1E4E8",[383],{"type":75,"value":384}," $(",{"type":61,"tag":323,"props":386,"children":387},{"style":340},[388],{"type":75,"value":343},{"type":61,"tag":323,"props":390,"children":391},{"style":346},[392],{"type":75,"value":393}," -ti",{"type":61,"tag":323,"props":395,"children":396},{"style":352},[397],{"type":75,"value":398}," :3001",{"type":61,"tag":323,"props":400,"children":401},{"style":381},[402],{"type":75,"value":403},")\n",{"type":61,"tag":313,"props":405,"children":409},{"className":406,"code":407,"language":408,"meta":7,"style":7},"language-powershell shiki shiki-themes github-dark","# Windows\nnetstat -ano | findstr :3001\ntaskkill /PID \u003Cpid> /F\n","powershell",[410],{"type":61,"tag":70,"props":411,"children":412},{"__ignoreMap":7},[413,421,429],{"type":61,"tag":323,"props":414,"children":415},{"class":325,"line":326},[416],{"type":61,"tag":323,"props":417,"children":418},{},[419],{"type":75,"value":420},"# Windows\n",{"type":61,"tag":323,"props":422,"children":423},{"class":325,"line":336},[424],{"type":61,"tag":323,"props":425,"children":426},{},[427],{"type":75,"value":428},"netstat -ano | findstr :3001\n",{"type":61,"tag":323,"props":430,"children":431},{"class":325,"line":367},[432],{"type":61,"tag":323,"props":433,"children":434},{},[435],{"type":75,"value":436},"taskkill /PID \u003Cpid> /F\n",{"type":61,"tag":62,"props":438,"children":439},{},[440,442,448,450,456,457,463,465,471],{"type":75,"value":441},"If you keep ending up on 3001 by accident, the real fix is to find what holds 3000, often a dev server from another project or a crashed ",{"type":61,"tag":70,"props":443,"children":445},{"className":444},[],[446],{"type":75,"value":447},"next dev",{"type":75,"value":449},". To fix the port on purpose: ",{"type":61,"tag":70,"props":451,"children":453},{"className":452},[],[454],{"type":75,"value":455},"PORT=3001 npm start",{"type":75,"value":250},{"type":61,"tag":70,"props":458,"children":460},{"className":459},[],[461],{"type":75,"value":462},"next dev -p 3001",{"type":75,"value":464},", or ",{"type":61,"tag":70,"props":466,"children":468},{"className":467},[],[469],{"type":75,"value":470},"app.listen(process.env.PORT || 3001)",{"type":75,"value":472}," in Express.",{"type":61,"tag":89,"props":474,"children":476},{"id":475},"frontend-on-3000-api-on-3001",[477],{"type":75,"value":478},"Frontend on 3000, API on 3001",{"type":61,"tag":62,"props":480,"children":481},{},[482,484,489,491,496,498,504],{"type":75,"value":483},"Browsers treat ",{"type":61,"tag":70,"props":485,"children":487},{"className":486},[],[488],{"type":75,"value":27},{"type":75,"value":490}," and ",{"type":61,"tag":70,"props":492,"children":494},{"className":493},[],[495],{"type":75,"value":11},{"type":75,"value":497}," as different origins, so ",{"type":61,"tag":70,"props":499,"children":501},{"className":500},[],[502],{"type":75,"value":503},"fetch('http://localhost:3001/api')",{"type":75,"value":505}," from the frontend triggers CORS. Two clean options:",{"type":61,"tag":507,"props":508,"children":509},"ul",{},[510,552],{"type":61,"tag":207,"props":511,"children":512},{},[513,518,520,526,528,534,536,542,544,550],{"type":61,"tag":66,"props":514,"children":515},{},[516],{"type":75,"value":517},"Proxy through the frontend dev server.",{"type":75,"value":519}," Vite's ",{"type":61,"tag":70,"props":521,"children":523},{"className":522},[],[524],{"type":75,"value":525},"server.proxy",{"type":75,"value":527},", Next.js ",{"type":61,"tag":70,"props":529,"children":531},{"className":530},[],[532],{"type":75,"value":533},"rewrites",{"type":75,"value":535},", or CRA's ",{"type":61,"tag":70,"props":537,"children":539},{"className":538},[],[540],{"type":75,"value":541},"\"proxy\": \"http://localhost:3001\"",{"type":75,"value":543}," in ",{"type":61,"tag":70,"props":545,"children":547},{"className":546},[],[548],{"type":75,"value":549},"package.json",{"type":75,"value":551},". The browser sees one origin and cookies just work.",{"type":61,"tag":207,"props":553,"children":554},{},[555,560,562,568,570,576],{"type":61,"tag":66,"props":556,"children":557},{},[558],{"type":75,"value":559},"Enable CORS on the API",{"type":75,"value":561}," for ",{"type":61,"tag":70,"props":563,"children":565},{"className":564},[],[566],{"type":75,"value":567},"http://localhost:3000",{"type":75,"value":569}," only, not ",{"type":61,"tag":70,"props":571,"children":573},{"className":572},[],[574],{"type":75,"value":575},"*",{"type":75,"value":577},", especially if you send cookies.",{"type":61,"tag":89,"props":579,"children":581},{"id":580},"open-localhost3001-from-another-device",[582],{"type":75,"value":583},"Open localhost:3001 from another device",{"type":61,"tag":62,"props":585,"children":586},{},[587,589,595,596,602,603,609,611,617,619,625,627,632],{"type":75,"value":588},"Bind the server to all interfaces (",{"type":61,"tag":70,"props":590,"children":592},{"className":591},[],[593],{"type":75,"value":594},"HOST=0.0.0.0",{"type":75,"value":250},{"type":61,"tag":70,"props":597,"children":599},{"className":598},[],[600],{"type":75,"value":601},"next dev -H 0.0.0.0",{"type":75,"value":464},{"type":61,"tag":70,"props":604,"children":606},{"className":605},[],[607],{"type":75,"value":608},"app.listen(3001, '0.0.0.0')",{"type":75,"value":610},"), then open ",{"type":61,"tag":70,"props":612,"children":614},{"className":613},[],[615],{"type":75,"value":616},"http://YOUR-LAN-IP:3001",{"type":75,"value":618}," from a device on the same network. If the frontend calls the API as ",{"type":61,"tag":70,"props":620,"children":622},{"className":621},[],[623],{"type":75,"value":624},"http://localhost:3001",{"type":75,"value":626},", it breaks on the phone, because the phone's ",{"type":61,"tag":70,"props":628,"children":630},{"className":629},[],[631],{"type":75,"value":5},{"type":75,"value":633}," is the phone. Use the proxy approach above or a relative URL.",{"type":61,"tag":89,"props":635,"children":637},{"id":636},"share-3001-or-receive-webhooks-on-it",[638],{"type":75,"value":639},"Share 3001 or receive webhooks on it",{"type":61,"tag":62,"props":641,"children":642},{},[643],{"type":75,"value":644},"When the frontend is on 3000 and the API on 3001, webhooks from Stripe, GitHub or Shopify should go straight to the API:",{"type":61,"tag":313,"props":646,"children":648},{"className":315,"code":647,"language":317,"meta":7,"style":7},"relay forward --bucket my-api http://localhost:3001/webhooks\n",[649],{"type":61,"tag":70,"props":650,"children":651},{"__ignoreMap":7},[652],{"type":61,"tag":323,"props":653,"children":654},{"class":325,"line":326},[655,660,665,670,675],{"type":61,"tag":323,"props":656,"children":657},{"style":340},[658],{"type":75,"value":659},"relay",{"type":61,"tag":323,"props":661,"children":662},{"style":352},[663],{"type":75,"value":664}," forward",{"type":61,"tag":323,"props":666,"children":667},{"style":346},[668],{"type":75,"value":669}," --bucket",{"type":61,"tag":323,"props":671,"children":672},{"style":352},[673],{"type":75,"value":674}," my-api",{"type":61,"tag":323,"props":676,"children":677},{"style":352},[678],{"type":75,"value":679}," http://localhost:3001/webhooks\n",{"type":61,"tag":62,"props":681,"children":682},{},[683,685,690],{"type":75,"value":684},"The bucket has a permanent public URL that you paste into the provider once. Each webhook is delivered to port 3001 and logged, so you can replay it while you iterate. See ",{"type":61,"tag":137,"props":686,"children":687},{"href":21},[688],{"type":75,"value":689},"receive webhooks on localhost",{"type":75,"value":691},".",{"type":61,"tag":62,"props":693,"children":694},{},[695],{"type":75,"value":696},"To share a running app, tunnel it:",{"type":61,"tag":313,"props":698,"children":700},{"className":315,"code":699,"language":317,"meta":7,"style":7},"relay connect --name my-app http://localhost:3001\n",[701],{"type":61,"tag":70,"props":702,"children":703},{"__ignoreMap":7},[704],{"type":61,"tag":323,"props":705,"children":706},{"class":325,"line":326},[707,711,716,721,726],{"type":61,"tag":323,"props":708,"children":709},{"style":340},[710],{"type":75,"value":659},{"type":61,"tag":323,"props":712,"children":713},{"style":352},[714],{"type":75,"value":715}," connect",{"type":61,"tag":323,"props":717,"children":718},{"style":346},[719],{"type":75,"value":720}," --name",{"type":61,"tag":323,"props":722,"children":723},{"style":352},[724],{"type":75,"value":725}," my-app",{"type":61,"tag":323,"props":727,"children":728},{"style":352},[729],{"type":75,"value":730}," http://localhost:3001\n",{"type":61,"tag":62,"props":732,"children":733},{},[734],{"type":75,"value":735},"For a split frontend and API, tunnel the frontend and let its dev-server proxy reach the API locally. That way you need only one public URL.",{"type":61,"tag":737,"props":738,"children":739},"style",{},[740],{"type":75,"value":741},"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);}",{"title":7,"searchDepth":367,"depth":367,"links":743},[744,745,746,747,748,749],{"id":91,"depth":336,"text":94},{"id":198,"depth":336,"text":201},{"id":308,"depth":336,"text":311},{"id":475,"depth":336,"text":478},{"id":580,"depth":336,"text":583},{"id":636,"depth":336,"text":639},"markdown","content:localhost:3001.md","content","localhost/3001.md","localhost/3001","md",{"loc":4},1793199809178]