[{"data":1,"prerenderedAt":5180},["ShallowReactive",2],{"blog-list":3},[4,1513,3246],{"id":5,"title":6,"body":7,"canonical":1501,"date":1502,"description":1503,"draft":1504,"extension":1505,"lang":1506,"meta":1507,"navigation":326,"path":1508,"readingTime":1509,"seo":1510,"stem":1511,"__hash__":1512},"blog\u002Fblog\u002Fbeing-heard.md","Being Heard Isn't Just About Speaking — It's About Understanding",{"type":8,"value":9,"toc":1482},"minimark",[10,15,23,26,38,41,44,47,50,70,75,78,84,88,95,113,117,120,131,134,138,141,144,168,171,178,182,188,194,198,201,208,269,273,276,283,376,380,383,390,499,506,588,592,595,678,682,685,692,910,914,917,1190,1194,1197,1202,1357,1362,1446,1450,1457,1465,1469,1472,1475,1478],[11,12,14],"h3",{"id":13},"from-human-connection-to-multilingual-ux-using-nextjs-and-next-intl-to-build-user-aware-language-ready-web-experiences","From human connection to multilingual UX — using Next.js and next-intl to build user-aware, language-ready web experiences.",[16,17,18],"p",{},[19,20],"img",{"alt":21,"src":22},"","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F730\u002F1*MlejWnprLa0VZpKGNdt9vg.png",[16,24,25],{},"I've always loved to be heard — not just in the sense of speaking, but in a way that makes me feel understood. We all do. It's human nature. But more often than not, I've found myself in conversations where I wasn't truly listened to. I was acknowledged, but not understood.",[16,27,28,29,33,34,37],{},"There was a time when I kept explaining myself over and over, hoping the other person would get it. But they were listening through their own filter — hearing what they wanted, not what I was actually saying. And I realized something: Most of us communicate the way ",[30,31,32],"em",{},"we"," want to be heard, instead of listening the way ",[30,35,36],{},"someone else"," wants to be understood.",[16,39,40],{},"But what if we chose to listen differently? What if, instead of assuming, we asked? What if we designed experiences that didn't just express what we wanted to say, but adapted to the way others understood best?",[16,42,43],{},"Just like in personal conversations, the way we design digital experiences determines whether users feel understood. Imagine visiting a website that doesn't support your language. You might understand bits and pieces, but the experience feels foreign, even alienating.",[16,45,46],{},"So, what does it really mean to listen? It's more than just acknowledging the presence of another — it's about making them feel at home, like they belong. In the digital world, listening means adapting to the user's needs, not expecting them to adapt to us.",[16,48,49],{},"Think about it: When you walk into a space where everything is unfamiliar — the language, the signs, the way things work — it takes extra effort just to navigate. You feel like an outsider. But when that same space acknowledges your language, your culture, and your way of thinking, suddenly, it feels welcoming. It feels like it was made for you.",[16,51,52,53,60,61,69],{},"That's why ",[54,55,59],"a",{"href":56,"rel":57},"https:\u002F\u002Fwww.techtarget.com\u002Fwhatis\u002Fdefinition\u002Finternationalization-I18N",[58],"nofollow","internationalization (i18n)"," is so powerful. It's not just about translating words — it's about creating an experience that listens to the user, understands them, and speaks to them in a way that feels natural. And for Next.js developers, one of the best ways to achieve this is through ",[54,62,65],{"href":63,"rel":64},"https:\u002F\u002Fnext-intl.dev\u002Fdocs\u002Fgetting-started",[58],[66,67,68],"strong",{},"next-intl",".",[71,72,74],"h2",{"id":73},"how-do-we-start-listening","How Do We Start Listening?",[16,76,77],{},"Just like in any conversation, there are different ways to listen. Sometimes, we listen through direct engagement — asking questions, responding in real time. Other times, we listen passively — observing patterns, understanding behavior, and adapting accordingly.",[16,79,80,81,83],{},"With ",[66,82,68],{},", we have similar choices when it comes to internationalization. We can structure our applications in a way that prioritizes adaptability, ensuring users feel like the experience was crafted for them. In Next.js, this comes down to two key approaches:",[11,85,87],{"id":86},"with-i18n-routing-letting-the-url-speak","With i18n Routing → Letting the URL Speak",[16,89,90,91,94],{},"This approach integrates the language directly into the app's navigation. Just like entering a space where the signs immediately tell you, ",[30,92,93],{},"\"We speak your language,\""," this method ensures users instantly see content in their preferred language.",[96,97,98,107,110],"ul",{},[99,100,101,102,106],"li",{},"Uses a top-level ",[103,104,105],"span",{},"locale"," segment for prefixed pathnames, such as \u002Fen\u002Fabout or \u002Fes\u002Fcontact.",[99,108,109],{},"Supports domain-based routing, like en.example.com\u002Fabout for region-specific experiences.",[99,111,112],{},"Ideal for applications that need clear and structured multilingual navigation.",[11,114,116],{"id":115},"without-i18n-routing-listening-to-user-preferences","Without i18n Routing → Listening to User Preferences",[16,118,119],{},"Not every conversation starts with words; sometimes, we listen by observing. This approach allows applications to detect and adapt to a user's language preference dynamically.",[96,121,122,125,128],{},[99,123,124],{},"Useful for apps that rely on user settings to determine language.",[99,126,127],{},"Works well for single-language applications that may need flexibility in the future.",[99,129,130],{},"Keeps URLs clean and language-independent, shifting the focus to user choice rather than URL structure.",[16,132,133],{},"Both methods have their place, just like different ways of listening in conversation. The key is to choose the one that best fits the needs of your users — because in the end, it's not just about what we build, but how we make people feel understood.",[71,135,137],{"id":136},"getting-started-learning-to-listen-through-code","Getting Started: Learning to Listen Through Code",[16,139,140],{},"Just like in any meaningful conversation, listening starts with intention. In the world of applications, that intention shows up when we choose to support multiple languages — when we decide that users from anywhere should feel like the experience was designed with them in mind.",[16,142,143],{},"With Next.js and next-intl, that journey begins simply:",[145,146,150],"pre",{"className":147,"code":148,"language":149,"meta":21,"style":21},"language-bash shiki shiki-themes github-light github-dark","npm install next-intl\n","bash",[151,152,153],"code",{"__ignoreMap":21},[103,154,157,161,165],{"class":155,"line":156},"line",1,[103,158,160],{"class":159},"sScJk","npm",[103,162,164],{"class":163},"sZZnC"," install",[103,166,167],{"class":163}," next-intl\n",[16,169,170],{},"But just like human conversations, how we listen matters just as much as what we hear. Next-intl gives us two ways to approach internationalization: one that makes language visible, and another that quietly adapts based on the user's preferences.",[16,172,173,174,177],{},"Let's begin with the first: ",[66,175,176],{},"i18n Routing"," — a way to let language speak through the URL itself.",[71,179,181],{"id":180},"with-i18n-routing-making-language-part-of-the-experience","With i18n Routing: Making Language Part of the Experience",[16,183,184,185],{},"When users land on a page and immediately see content in their language — like \u002Fen\u002Fabout or \u002Fes\u002Fcontact—they know: ",[30,186,187],{},"\"This space speaks to me.\"",[16,189,190,191,193],{},"This approach brings language into the very fabric of navigation, using a top-level ",[103,192,105],{}," segment in your Next.js routes. Setting it up is easier than it sounds.",[11,195,197],{"id":196},"step-1-define-your-messages","Step 1: Define Your Messages",[16,199,200],{},"Each language gets its own JSON file. Here's a simple example:",[16,202,203],{},[30,204,205],{},[66,206,207],{},"messages\u002Fen.json:",[145,209,213],{"className":210,"code":211,"language":212,"meta":21,"style":21},"language-json shiki shiki-themes github-light github-dark","{\n  \"HomePage\": {\n    \"title\": \"Hello world!\",\n    \"about\": \"Go to the about page\"\n  }\n}\n","json",[151,214,215,221,231,246,257,263],{"__ignoreMap":21},[103,216,217],{"class":155,"line":156},[103,218,220],{"class":219},"sVt8B","{\n",[103,222,224,228],{"class":155,"line":223},2,[103,225,227],{"class":226},"sj4cs","  \"HomePage\"",[103,229,230],{"class":219},": {\n",[103,232,234,237,240,243],{"class":155,"line":233},3,[103,235,236],{"class":226},"    \"title\"",[103,238,239],{"class":219},": ",[103,241,242],{"class":163},"\"Hello world!\"",[103,244,245],{"class":219},",\n",[103,247,249,252,254],{"class":155,"line":248},4,[103,250,251],{"class":226},"    \"about\"",[103,253,239],{"class":219},[103,255,256],{"class":163},"\"Go to the about page\"\n",[103,258,260],{"class":155,"line":259},5,[103,261,262],{"class":219},"  }\n",[103,264,266],{"class":155,"line":265},6,[103,267,268],{"class":219},"}\n",[11,270,272],{"id":271},"step-2-configure-nextjs-for-locales","Step 2: Configure Next.js for Locales",[16,274,275],{},"With next-intl, we wrap our config to enable locale-based routing.",[16,277,278],{},[30,279,280],{},[66,281,282],{},"next.config.ts",[145,284,288],{"className":285,"code":286,"language":287,"meta":21,"style":21},"language-ts shiki shiki-themes github-light github-dark","import { NextConfig } from 'next';\nimport createNextIntlPlugin from 'next-intl\u002Fplugin';\n\nconst nextConfig: NextConfig = {};\nconst withNextIntl = createNextIntlPlugin();\nexport default withNextIntl(nextConfig);\n","ts",[151,289,290,308,322,328,348,363],{"__ignoreMap":21},[103,291,292,296,299,302,305],{"class":155,"line":156},[103,293,295],{"class":294},"szBVR","import",[103,297,298],{"class":219}," { NextConfig } ",[103,300,301],{"class":294},"from",[103,303,304],{"class":163}," 'next'",[103,306,307],{"class":219},";\n",[103,309,310,312,315,317,320],{"class":155,"line":223},[103,311,295],{"class":294},[103,313,314],{"class":219}," createNextIntlPlugin ",[103,316,301],{"class":294},[103,318,319],{"class":163}," 'next-intl\u002Fplugin'",[103,321,307],{"class":219},[103,323,324],{"class":155,"line":233},[103,325,327],{"emptyLinePlaceholder":326},true,"\n",[103,329,330,333,336,339,342,345],{"class":155,"line":248},[103,331,332],{"class":294},"const",[103,334,335],{"class":226}," nextConfig",[103,337,338],{"class":294},":",[103,340,341],{"class":159}," NextConfig",[103,343,344],{"class":294}," =",[103,346,347],{"class":219}," {};\n",[103,349,350,352,355,357,360],{"class":155,"line":259},[103,351,332],{"class":294},[103,353,354],{"class":226}," withNextIntl",[103,356,344],{"class":294},[103,358,359],{"class":159}," createNextIntlPlugin",[103,361,362],{"class":219},"();\n",[103,364,365,368,371,373],{"class":155,"line":265},[103,366,367],{"class":294},"export",[103,369,370],{"class":294}," default",[103,372,354],{"class":159},[103,374,375],{"class":219},"(nextConfig);\n",[11,377,379],{"id":378},"step-3-define-routing-and-navigation-behavior","Step 3: Define Routing and Navigation Behavior",[16,381,382],{},"Tell your app what languages it understands, and what to fall back on if it doesn't.",[16,384,385],{},[30,386,387],{},[66,388,389],{},"src\u002Fi18n\u002Frouting.ts",[145,391,393],{"className":285,"code":392,"language":287,"meta":21,"style":21},"import { defineRouting } from 'next-intl\u002Frouting';\nimport { createNavigation } from 'next-intl\u002Fnavigation';\n\nexport const routing = defineRouting({\n  \u002F\u002F list of all locales that are supported\n  locales: ['en', 'es', 'kr'],\n\n  \u002F\u002F Used when no locale matches, fallback to default\n  defaultLocale: 'en'\n});\n",[151,394,395,409,423,427,445,451,473,478,484,493],{"__ignoreMap":21},[103,396,397,399,402,404,407],{"class":155,"line":156},[103,398,295],{"class":294},[103,400,401],{"class":219}," { defineRouting } ",[103,403,301],{"class":294},[103,405,406],{"class":163}," 'next-intl\u002Frouting'",[103,408,307],{"class":219},[103,410,411,413,416,418,421],{"class":155,"line":223},[103,412,295],{"class":294},[103,414,415],{"class":219}," { createNavigation } ",[103,417,301],{"class":294},[103,419,420],{"class":163}," 'next-intl\u002Fnavigation'",[103,422,307],{"class":219},[103,424,425],{"class":155,"line":233},[103,426,327],{"emptyLinePlaceholder":326},[103,428,429,431,434,437,439,442],{"class":155,"line":248},[103,430,367],{"class":294},[103,432,433],{"class":294}," const",[103,435,436],{"class":226}," routing",[103,438,344],{"class":294},[103,440,441],{"class":159}," defineRouting",[103,443,444],{"class":219},"({\n",[103,446,447],{"class":155,"line":259},[103,448,450],{"class":449},"sJ8bj","  \u002F\u002F list of all locales that are supported\n",[103,452,453,456,459,462,465,467,470],{"class":155,"line":265},[103,454,455],{"class":219},"  locales: [",[103,457,458],{"class":163},"'en'",[103,460,461],{"class":219},", ",[103,463,464],{"class":163},"'es'",[103,466,461],{"class":219},[103,468,469],{"class":163},"'kr'",[103,471,472],{"class":219},"],\n",[103,474,476],{"class":155,"line":475},7,[103,477,327],{"emptyLinePlaceholder":326},[103,479,481],{"class":155,"line":480},8,[103,482,483],{"class":449},"  \u002F\u002F Used when no locale matches, fallback to default\n",[103,485,487,490],{"class":155,"line":486},9,[103,488,489],{"class":219},"  defaultLocale: ",[103,491,492],{"class":163},"'en'\n",[103,494,496],{"class":155,"line":495},10,[103,497,498],{"class":219},"});\n",[16,500,501],{},[30,502,503],{},[66,504,505],{},"src\u002Fi18n\u002Fnavigation.ts",[145,507,509],{"className":285,"code":508,"language":287,"meta":21,"style":21},"import {createNavigation} from 'next-intl\u002Fnavigation';\nimport {routing} from '.\u002Frouting';\n\nexport const {Link, redirect, usePathname, useRouter, getPathname} =\n  createNavigation(routing);\n",[151,510,511,524,538,542,580],{"__ignoreMap":21},[103,512,513,515,518,520,522],{"class":155,"line":156},[103,514,295],{"class":294},[103,516,517],{"class":219}," {createNavigation} ",[103,519,301],{"class":294},[103,521,420],{"class":163},[103,523,307],{"class":219},[103,525,526,528,531,533,536],{"class":155,"line":223},[103,527,295],{"class":294},[103,529,530],{"class":219}," {routing} ",[103,532,301],{"class":294},[103,534,535],{"class":163}," '.\u002Frouting'",[103,537,307],{"class":219},[103,539,540],{"class":155,"line":233},[103,541,327],{"emptyLinePlaceholder":326},[103,543,544,546,548,551,554,556,559,561,564,566,569,571,574,577],{"class":155,"line":248},[103,545,367],{"class":294},[103,547,433],{"class":294},[103,549,550],{"class":219}," {",[103,552,553],{"class":226},"Link",[103,555,461],{"class":219},[103,557,558],{"class":226},"redirect",[103,560,461],{"class":219},[103,562,563],{"class":226},"usePathname",[103,565,461],{"class":219},[103,567,568],{"class":226},"useRouter",[103,570,461],{"class":219},[103,572,573],{"class":226},"getPathname",[103,575,576],{"class":219},"} ",[103,578,579],{"class":294},"=\n",[103,581,582,585],{"class":155,"line":259},[103,583,584],{"class":159},"  createNavigation",[103,586,587],{"class":219},"(routing);\n",[11,589,591],{"id":590},"step-4-middleware-that-adapts-like-a-good-listener","Step 4: Middleware That Adapts Like a Good Listener",[16,593,594],{},"Middleware lets your app greet users in their language from the very first request.",[145,596,598],{"className":285,"code":597,"language":287,"meta":21,"style":21},"import createMiddleware from \"next-intl\u002Fmiddleware\";\nimport { routing } from \".\u002Fi18n\u002Frouting\";\n\nexport default createMiddleware(routing);\nexport const config = {\n matcher: [\"\u002F((?!_next|api|ingest|.*\\\\..*).*)\"],\n};\n",[151,599,600,614,628,632,643,657,673],{"__ignoreMap":21},[103,601,602,604,607,609,612],{"class":155,"line":156},[103,603,295],{"class":294},[103,605,606],{"class":219}," createMiddleware ",[103,608,301],{"class":294},[103,610,611],{"class":163}," \"next-intl\u002Fmiddleware\"",[103,613,307],{"class":219},[103,615,616,618,621,623,626],{"class":155,"line":223},[103,617,295],{"class":294},[103,619,620],{"class":219}," { routing } ",[103,622,301],{"class":294},[103,624,625],{"class":163}," \".\u002Fi18n\u002Frouting\"",[103,627,307],{"class":219},[103,629,630],{"class":155,"line":233},[103,631,327],{"emptyLinePlaceholder":326},[103,633,634,636,638,641],{"class":155,"line":248},[103,635,367],{"class":294},[103,637,370],{"class":294},[103,639,640],{"class":159}," createMiddleware",[103,642,587],{"class":219},[103,644,645,647,649,652,654],{"class":155,"line":259},[103,646,367],{"class":294},[103,648,433],{"class":294},[103,650,651],{"class":226}," config",[103,653,344],{"class":294},[103,655,656],{"class":219}," {\n",[103,658,659,662,665,668,671],{"class":155,"line":265},[103,660,661],{"class":219}," matcher: [",[103,663,664],{"class":163},"\"\u002F((?!_next|api|ingest|.*",[103,666,667],{"class":226},"\\\\",[103,669,670],{"class":163},"..*).*)\"",[103,672,472],{"class":219},[103,674,675],{"class":155,"line":475},[103,676,677],{"class":219},"};\n",[11,679,681],{"id":680},"step-5-responding-based-on-locale-context","Step 5: Responding Based on Locale Context",[16,683,684],{},"Server components need to know what language they're speaking. That's where request.ts comes in.",[16,686,687],{},[30,688,689],{},[66,690,691],{},"src\u002Fi18n\u002Frequest.ts",[145,693,695],{"className":285,"code":694,"language":287,"meta":21,"style":21},"import type { Locale } from \"@\u002Fmessages\u002F_schema\";\nimport { getRequestConfig } from \"next-intl\u002Fserver\";\nimport { routing } from \".\u002Frouting\";\n\nexport default getRequestConfig(async ({ requestLocale }) => {\n \u002F\u002F This typically corresponds to the `[locale]` segment\n let locale = await requestLocale;\n\n if (!locale || !routing.locales.includes(locale as Locale)) {\n  locale = routing.defaultLocale;\n }\n\nreturn {\n  locale,\n  messages: (await import(`..\u002Fmessages\u002F${locale}.json`)).default,\n };\n});\n",[151,696,697,714,728,741,745,775,780,797,801,839,849,855,860,868,874,899,905],{"__ignoreMap":21},[103,698,699,701,704,707,709,712],{"class":155,"line":156},[103,700,295],{"class":294},[103,702,703],{"class":294}," type",[103,705,706],{"class":219}," { Locale } ",[103,708,301],{"class":294},[103,710,711],{"class":163}," \"@\u002Fmessages\u002F_schema\"",[103,713,307],{"class":219},[103,715,716,718,721,723,726],{"class":155,"line":223},[103,717,295],{"class":294},[103,719,720],{"class":219}," { getRequestConfig } ",[103,722,301],{"class":294},[103,724,725],{"class":163}," \"next-intl\u002Fserver\"",[103,727,307],{"class":219},[103,729,730,732,734,736,739],{"class":155,"line":233},[103,731,295],{"class":294},[103,733,620],{"class":219},[103,735,301],{"class":294},[103,737,738],{"class":163}," \".\u002Frouting\"",[103,740,307],{"class":219},[103,742,743],{"class":155,"line":248},[103,744,327],{"emptyLinePlaceholder":326},[103,746,747,749,751,754,757,760,763,767,770,773],{"class":155,"line":259},[103,748,367],{"class":294},[103,750,370],{"class":294},[103,752,753],{"class":159}," getRequestConfig",[103,755,756],{"class":219},"(",[103,758,759],{"class":294},"async",[103,761,762],{"class":219}," ({ ",[103,764,766],{"class":765},"s4XuR","requestLocale",[103,768,769],{"class":219}," }) ",[103,771,772],{"class":294},"=>",[103,774,656],{"class":219},[103,776,777],{"class":155,"line":265},[103,778,779],{"class":449}," \u002F\u002F This typically corresponds to the `[locale]` segment\n",[103,781,782,785,788,791,794],{"class":155,"line":475},[103,783,784],{"class":294}," let",[103,786,787],{"class":219}," locale ",[103,789,790],{"class":294},"=",[103,792,793],{"class":294}," await",[103,795,796],{"class":219}," requestLocale;\n",[103,798,799],{"class":155,"line":480},[103,800,327],{"emptyLinePlaceholder":326},[103,802,803,806,809,812,815,818,821,824,827,830,833,836],{"class":155,"line":486},[103,804,805],{"class":294}," if",[103,807,808],{"class":219}," (",[103,810,811],{"class":294},"!",[103,813,814],{"class":219},"locale ",[103,816,817],{"class":294},"||",[103,819,820],{"class":294}," !",[103,822,823],{"class":219},"routing.locales.",[103,825,826],{"class":159},"includes",[103,828,829],{"class":219},"(locale ",[103,831,832],{"class":294},"as",[103,834,835],{"class":159}," Locale",[103,837,838],{"class":219},")) {\n",[103,840,841,844,846],{"class":155,"line":495},[103,842,843],{"class":219},"  locale ",[103,845,790],{"class":294},[103,847,848],{"class":219}," routing.defaultLocale;\n",[103,850,852],{"class":155,"line":851},11,[103,853,854],{"class":219}," }\n",[103,856,858],{"class":155,"line":857},12,[103,859,327],{"emptyLinePlaceholder":326},[103,861,863,866],{"class":155,"line":862},13,[103,864,865],{"class":294},"return",[103,867,656],{"class":219},[103,869,871],{"class":155,"line":870},14,[103,872,873],{"class":219},"  locale,\n",[103,875,877,880,883,886,888,891,893,896],{"class":155,"line":876},15,[103,878,879],{"class":219},"  messages: (",[103,881,882],{"class":294},"await",[103,884,885],{"class":294}," import",[103,887,756],{"class":219},[103,889,890],{"class":163},"`..\u002Fmessages\u002F${",[103,892,105],{"class":219},[103,894,895],{"class":163},"}.json`",[103,897,898],{"class":219},")).default,\n",[103,900,902],{"class":155,"line":901},16,[103,903,904],{"class":219}," };\n",[103,906,908],{"class":155,"line":907},17,[103,909,498],{"class":219},[11,911,913],{"id":912},"step-6-set-up-your-locale-layout","Step 6: Set Up Your Locale Layout",[16,915,916],{},"Now we make sure every page honors the selected language.",[145,918,922],{"className":919,"code":920,"language":921,"meta":21,"style":21},"language-tsx shiki shiki-themes github-light github-dark","import {NextIntlClientProvider, hasLocale} from 'next-intl';\nimport {notFound} from 'next\u002Fnavigation';\nimport {routing} from '@\u002Fi18n\u002Frouting';\n\nexport default async function LocaleLayout({\n  children,\n  params\n}: {\n  children: React.ReactNode;\n  params: Promise\u003C{locale: string}>;\n}) {\n  \u002F\u002F Ensure that the incoming `locale` is valid\n  const {locale} = await params;\n  if (!hasLocale(routing.locales, locale)) {\n    notFound();\n  }\n\n  return (\n    \u003Chtml lang={locale}>\n      \u003Cbody>\n        \u003CNextIntlClientProvider>{children}\u003C\u002FNextIntlClientProvider>\n      \u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n","tsx",[151,923,924,938,952,965,969,986,993,998,1007,1023,1046,1051,1056,1074,1089,1096,1100,1104,1113,1131,1143,1159,1169,1179,1185],{"__ignoreMap":21},[103,925,926,928,931,933,936],{"class":155,"line":156},[103,927,295],{"class":294},[103,929,930],{"class":219}," {NextIntlClientProvider, hasLocale} ",[103,932,301],{"class":294},[103,934,935],{"class":163}," 'next-intl'",[103,937,307],{"class":219},[103,939,940,942,945,947,950],{"class":155,"line":223},[103,941,295],{"class":294},[103,943,944],{"class":219}," {notFound} ",[103,946,301],{"class":294},[103,948,949],{"class":163}," 'next\u002Fnavigation'",[103,951,307],{"class":219},[103,953,954,956,958,960,963],{"class":155,"line":233},[103,955,295],{"class":294},[103,957,530],{"class":219},[103,959,301],{"class":294},[103,961,962],{"class":163}," '@\u002Fi18n\u002Frouting'",[103,964,307],{"class":219},[103,966,967],{"class":155,"line":248},[103,968,327],{"emptyLinePlaceholder":326},[103,970,971,973,975,978,981,984],{"class":155,"line":259},[103,972,367],{"class":294},[103,974,370],{"class":294},[103,976,977],{"class":294}," async",[103,979,980],{"class":294}," function",[103,982,983],{"class":159}," LocaleLayout",[103,985,444],{"class":219},[103,987,988,991],{"class":155,"line":265},[103,989,990],{"class":765},"  children",[103,992,245],{"class":219},[103,994,995],{"class":155,"line":475},[103,996,997],{"class":765},"  params\n",[103,999,1000,1003,1005],{"class":155,"line":480},[103,1001,1002],{"class":219},"}",[103,1004,338],{"class":294},[103,1006,656],{"class":219},[103,1008,1009,1011,1013,1016,1018,1021],{"class":155,"line":486},[103,1010,990],{"class":765},[103,1012,338],{"class":294},[103,1014,1015],{"class":159}," React",[103,1017,69],{"class":219},[103,1019,1020],{"class":159},"ReactNode",[103,1022,307],{"class":219},[103,1024,1025,1028,1030,1033,1036,1038,1040,1043],{"class":155,"line":495},[103,1026,1027],{"class":765},"  params",[103,1029,338],{"class":294},[103,1031,1032],{"class":159}," Promise",[103,1034,1035],{"class":219},"\u003C{",[103,1037,105],{"class":765},[103,1039,338],{"class":294},[103,1041,1042],{"class":226}," string",[103,1044,1045],{"class":219},"}>;\n",[103,1047,1048],{"class":155,"line":851},[103,1049,1050],{"class":219},"}) {\n",[103,1052,1053],{"class":155,"line":857},[103,1054,1055],{"class":449},"  \u002F\u002F Ensure that the incoming `locale` is valid\n",[103,1057,1058,1061,1063,1065,1067,1069,1071],{"class":155,"line":862},[103,1059,1060],{"class":294},"  const",[103,1062,550],{"class":219},[103,1064,105],{"class":226},[103,1066,576],{"class":219},[103,1068,790],{"class":294},[103,1070,793],{"class":294},[103,1072,1073],{"class":219}," params;\n",[103,1075,1076,1079,1081,1083,1086],{"class":155,"line":870},[103,1077,1078],{"class":294},"  if",[103,1080,808],{"class":219},[103,1082,811],{"class":294},[103,1084,1085],{"class":159},"hasLocale",[103,1087,1088],{"class":219},"(routing.locales, locale)) {\n",[103,1090,1091,1094],{"class":155,"line":876},[103,1092,1093],{"class":159},"    notFound",[103,1095,362],{"class":219},[103,1097,1098],{"class":155,"line":901},[103,1099,262],{"class":219},[103,1101,1102],{"class":155,"line":907},[103,1103,327],{"emptyLinePlaceholder":326},[103,1105,1107,1110],{"class":155,"line":1106},18,[103,1108,1109],{"class":294},"  return",[103,1111,1112],{"class":219}," (\n",[103,1114,1116,1119,1123,1126,1128],{"class":155,"line":1115},19,[103,1117,1118],{"class":219},"    \u003C",[103,1120,1122],{"class":1121},"s9eBZ","html",[103,1124,1125],{"class":159}," lang",[103,1127,790],{"class":294},[103,1129,1130],{"class":219},"{locale}>\n",[103,1132,1134,1137,1140],{"class":155,"line":1133},20,[103,1135,1136],{"class":219},"      \u003C",[103,1138,1139],{"class":1121},"body",[103,1141,1142],{"class":219},">\n",[103,1144,1146,1149,1152,1155,1157],{"class":155,"line":1145},21,[103,1147,1148],{"class":219},"        \u003C",[103,1150,1151],{"class":226},"NextIntlClientProvider",[103,1153,1154],{"class":219},">{children}\u003C\u002F",[103,1156,1151],{"class":226},[103,1158,1142],{"class":219},[103,1160,1162,1165,1167],{"class":155,"line":1161},22,[103,1163,1164],{"class":219},"      \u003C\u002F",[103,1166,1139],{"class":1121},[103,1168,1142],{"class":219},[103,1170,1172,1175,1177],{"class":155,"line":1171},23,[103,1173,1174],{"class":219},"    \u003C\u002F",[103,1176,1122],{"class":1121},[103,1178,1142],{"class":219},[103,1180,1182],{"class":155,"line":1181},24,[103,1183,1184],{"class":219},"  );\n",[103,1186,1188],{"class":155,"line":1187},25,[103,1189,268],{"class":219},[11,1191,1193],{"id":1192},"step-7-let-your-users-feel-heard","Step 7: Let Your Users Feel Heard",[16,1195,1196],{},"In your components, bring the translations to life:",[16,1198,1199],{},[66,1200,1201],{},"Client Component",[145,1203,1205],{"className":919,"code":1204,"language":921,"meta":21,"style":21},"import {useTranslations} from 'next-intl';\nimport {Link} from '@\u002Fi18n\u002Fnavigation';\n\nexport default function HomePage() {\n  const t = useTranslations('HomePage');\n  return (\n    \u003Cdiv>\n      \u003Ch1>{t('title')}\u003C\u002Fh1>\n      \u003CLink href=\"\u002Fabout\">{t('about')}\u003C\u002FLink>\n    \u003C\u002Fdiv>\n  );\n}\n",[151,1206,1207,1220,1234,1238,1252,1272,1278,1287,1312,1341,1349,1353],{"__ignoreMap":21},[103,1208,1209,1211,1214,1216,1218],{"class":155,"line":156},[103,1210,295],{"class":294},[103,1212,1213],{"class":219}," {useTranslations} ",[103,1215,301],{"class":294},[103,1217,935],{"class":163},[103,1219,307],{"class":219},[103,1221,1222,1224,1227,1229,1232],{"class":155,"line":223},[103,1223,295],{"class":294},[103,1225,1226],{"class":219}," {Link} ",[103,1228,301],{"class":294},[103,1230,1231],{"class":163}," '@\u002Fi18n\u002Fnavigation'",[103,1233,307],{"class":219},[103,1235,1236],{"class":155,"line":233},[103,1237,327],{"emptyLinePlaceholder":326},[103,1239,1240,1242,1244,1246,1249],{"class":155,"line":248},[103,1241,367],{"class":294},[103,1243,370],{"class":294},[103,1245,980],{"class":294},[103,1247,1248],{"class":159}," HomePage",[103,1250,1251],{"class":219},"() {\n",[103,1253,1254,1256,1259,1261,1264,1266,1269],{"class":155,"line":259},[103,1255,1060],{"class":294},[103,1257,1258],{"class":226}," t",[103,1260,344],{"class":294},[103,1262,1263],{"class":159}," useTranslations",[103,1265,756],{"class":219},[103,1267,1268],{"class":163},"'HomePage'",[103,1270,1271],{"class":219},");\n",[103,1273,1274,1276],{"class":155,"line":265},[103,1275,1109],{"class":294},[103,1277,1112],{"class":219},[103,1279,1280,1282,1285],{"class":155,"line":475},[103,1281,1118],{"class":219},[103,1283,1284],{"class":1121},"div",[103,1286,1142],{"class":219},[103,1288,1289,1291,1294,1297,1300,1302,1305,1308,1310],{"class":155,"line":480},[103,1290,1136],{"class":219},[103,1292,1293],{"class":1121},"h1",[103,1295,1296],{"class":219},">{",[103,1298,1299],{"class":159},"t",[103,1301,756],{"class":219},[103,1303,1304],{"class":163},"'title'",[103,1306,1307],{"class":219},")}\u003C\u002F",[103,1309,1293],{"class":1121},[103,1311,1142],{"class":219},[103,1313,1314,1316,1318,1321,1323,1326,1328,1330,1332,1335,1337,1339],{"class":155,"line":486},[103,1315,1136],{"class":219},[103,1317,553],{"class":226},[103,1319,1320],{"class":159}," href",[103,1322,790],{"class":294},[103,1324,1325],{"class":163},"\"\u002Fabout\"",[103,1327,1296],{"class":219},[103,1329,1299],{"class":159},[103,1331,756],{"class":219},[103,1333,1334],{"class":163},"'about'",[103,1336,1307],{"class":219},[103,1338,553],{"class":226},[103,1340,1142],{"class":219},[103,1342,1343,1345,1347],{"class":155,"line":495},[103,1344,1174],{"class":219},[103,1346,1284],{"class":1121},[103,1348,1142],{"class":219},[103,1350,1351],{"class":155,"line":851},[103,1352,1184],{"class":219},[103,1354,1355],{"class":155,"line":857},[103,1356,268],{"class":219},[16,1358,1359],{},[66,1360,1361],{},"Server Component",[145,1363,1365],{"className":919,"code":1364,"language":921,"meta":21,"style":21},"import {getTranslations} from 'next-intl\u002Fserver';\n\nexport default async function HomePage() {\n  const t = await getTranslations('HomePage');\n  return \u003Ch1>{t('title')}\u003C\u002Fh1>;\n}\n",[151,1366,1367,1381,1385,1399,1418,1442],{"__ignoreMap":21},[103,1368,1369,1371,1374,1376,1379],{"class":155,"line":156},[103,1370,295],{"class":294},[103,1372,1373],{"class":219}," {getTranslations} ",[103,1375,301],{"class":294},[103,1377,1378],{"class":163}," 'next-intl\u002Fserver'",[103,1380,307],{"class":219},[103,1382,1383],{"class":155,"line":223},[103,1384,327],{"emptyLinePlaceholder":326},[103,1386,1387,1389,1391,1393,1395,1397],{"class":155,"line":233},[103,1388,367],{"class":294},[103,1390,370],{"class":294},[103,1392,977],{"class":294},[103,1394,980],{"class":294},[103,1396,1248],{"class":159},[103,1398,1251],{"class":219},[103,1400,1401,1403,1405,1407,1409,1412,1414,1416],{"class":155,"line":248},[103,1402,1060],{"class":294},[103,1404,1258],{"class":226},[103,1406,344],{"class":294},[103,1408,793],{"class":294},[103,1410,1411],{"class":159}," getTranslations",[103,1413,756],{"class":219},[103,1415,1268],{"class":163},[103,1417,1271],{"class":219},[103,1419,1420,1422,1425,1427,1429,1431,1433,1435,1437,1439],{"class":155,"line":259},[103,1421,1109],{"class":294},[103,1423,1424],{"class":219}," \u003C",[103,1426,1293],{"class":1121},[103,1428,1296],{"class":219},[103,1430,1299],{"class":159},[103,1432,756],{"class":219},[103,1434,1304],{"class":163},[103,1436,1307],{"class":219},[103,1438,1293],{"class":1121},[103,1440,1441],{"class":219},">;\n",[103,1443,1444],{"class":155,"line":265},[103,1445,268],{"class":219},[71,1447,1449],{"id":1448},"not-every-conversation-starts-with-a-word","Not Every Conversation Starts With a Word",[16,1451,1452,1453,1456],{},"Sometimes, the most thoughtful form of listening is quiet observation. Instead of putting the language in the URL, we let the app detect the user's preferences and adapt silently. This is where ",[66,1454,1455],{},"listening without i18n routing"," shines — cleaner URLs, language chosen by the user, and a more fluid experience for apps where explicit routing isn't needed.",[16,1458,1459,1460],{},"If that approach sounds more like the kind of experience you want to create, next-intl supports it beautifully. You can explore that approach here:\n👉 ",[54,1461,1464],{"href":1462,"rel":1463},"https:\u002F\u002Fnext-intl.dev\u002Fdocs\u002Fgetting-started\u002Fapp-router\u002Fwithout-i18n-routing",[58],"Listening Without i18n Routing →",[71,1466,1468],{"id":1467},"speak-their-language-feel-their-world","Speak Their Language, Feel Their World",[16,1470,1471],{},"In the end, being heard is about more than just the words we say — it's about how we make people feel. Whether it's through visible cues like URLs or quiet detection of preferences, the heart of internationalization is empathy. It's about designing with the listener in mind.",[16,1473,1474],{},"With next-intl and Next.js, you're not just building apps — you're creating spaces that speak to people, in their language, on their terms.",[16,1476,1477],{},"And that's the kind of conversation worth having.",[1479,1480,1481],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":21,"searchDepth":223,"depth":223,"links":1483},[1484,1485,1489,1490,1499,1500],{"id":13,"depth":233,"text":14},{"id":73,"depth":223,"text":74,"children":1486},[1487,1488],{"id":86,"depth":233,"text":87},{"id":115,"depth":233,"text":116},{"id":136,"depth":223,"text":137},{"id":180,"depth":223,"text":181,"children":1491},[1492,1493,1494,1495,1496,1497,1498],{"id":196,"depth":233,"text":197},{"id":271,"depth":233,"text":272},{"id":378,"depth":233,"text":379},{"id":590,"depth":233,"text":591},{"id":680,"depth":233,"text":681},{"id":912,"depth":233,"text":913},{"id":1192,"depth":233,"text":1193},{"id":1448,"depth":223,"text":1449},{"id":1467,"depth":223,"text":1468},"https:\u002F\u002Fiamlope.medium.com\u002Fbeing-heard-isnt-just-about-speaking-it-s-about-understanding-b700929c5743","2025-05-26","A guide to internationalization (i18n) in Next.js using next-intl to build multilingual, user-aware web experiences.",false,"md",null,{},"\u002Fblog\u002Fbeing-heard","6min",{"title":6,"description":1503},"blog\u002Fbeing-heard","BjXWRPicNvxmZuCMIRswV1C75TBXDzkCX3Odqr97uJg",{"id":1514,"title":1515,"body":1516,"canonical":3237,"date":3238,"description":3239,"draft":1504,"extension":1505,"lang":1506,"meta":3240,"navigation":326,"path":3241,"readingTime":3242,"seo":3243,"stem":3244,"__hash__":3245},"blog\u002Fblog\u002Fstop-yapping-lock-in.md","Stop yapping, Lock in",{"type":8,"value":1517,"toc":3225},[1518,1523,1528,1533,1536,1539,1542,1545,1548,1551,1554,1557,1560,1563,1567,1570,1573,1576,1579,1582,1585,1588,1591,1594,1597,1600,1603,1611,1614,1617,1620,1623,1627,1630,1633,1636,1639,1645,1648,1654,1674,1680,1683,1689,1696,1701,1704,1708,1711,1715,1721,1740,1744,1754,1779,1783,1786,1791,2009,2013,2016,2023,2365,2379,2397,3114,3118,3124,3129,3134,3139,3144,3148,3151,3154,3161,3168,3174,3179,3216,3222],[1519,1520,1522],"h4",{"id":1521},"keep-your-next-action-safe-weve-all-overshared-but-now-you-know-better-dont-cast-your-actions-be-legendary-and-anon","Keep your Next action safe — we've all overshared, but now you know better. Don't cast your actions… be legendary and anon.",[16,1524,1525],{},[19,1526],{"alt":21,"src":1527},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F736\u002F1*AYssJZ41GpzFIedW-rC-ig.jpeg",[16,1529,1530],{},[30,1531,1532],{},"stay locked in!",[16,1534,1535],{},"It's late at night. What could go wrong?",[16,1537,1538],{},"A chill evening, breezy winds outside. I'd just devoured a warm bowl of apples, chicken, and plantain, chased it with cold yoghurt. Life was vibing. My screen glowed with a beautiful anime scene, and everything just felt right. Soft belly, clear mind, nothing serious.",[16,1540,1541],{},"Then my phone lit up.\nA call from an old friend. Random, unexpected.",[16,1543,1544],{},"I picked up.\nWe talked. Laughed a little. Then out of nowhere, they said something. Not loud, not rude… just odd. Misplaced. One of those lines that slips through a crack in the moment and hits you sideways. I couldn't even react. I just sat there, phone to my ear, feeling this quiet shift from comfort to confusion.",[16,1546,1547],{},"I ended the call. Not angrily. Just… done.\nYou know that feeling, right? Where something harmless turns heavy. Where you suddenly realize you're more vulnerable than you thought.",[16,1549,1550],{},"It stuck with me. And it reminded me of another time.",[16,1552,1553],{},"Back in junior high, I said something wild about a teacher's daughter. I don't even know why. It just came out. The word got around, and I got dragged. I remember sitting in agriculture class that day, trying to focus on crop rotation while my brain was busy rotating my entire life. I wanted to disappear.",[16,1555,1556],{},"We still talk now, me and the person. We laugh about it. But I never forgot how one careless sentence changed everything for a while. It's wild how fast things can shift when you're unguarded. When you speak before filtering. When you share without thinking.",[16,1558,1559],{},"That's kind of how a lot of apps behave. You build something beautiful. A clean UI, smooth animations, everything chill. Then out of nowhere, a request comes in. Not a user you expected, not a flow you tested. And your server… just responds. Says too much. Does too much. No filters. No checks.",[16,1561,1562],{},"And just like that, you're leaking data. Performing actions you shouldn't. Breaking trust. Not because you meant to — but because you didn't stop to lock in.",[71,1564,1566],{"id":1565},"stop-yapping-your-servers-saying-too-much","Stop Yapping: Your Server's Saying Too Much",[16,1568,1569],{},"See, it's easy to laugh at a wild comment in a conversation or a slip-up back in junior high — until your app does the exact same thing.",[16,1571,1572],{},"You start with good intentions. You've been building for days, maybe weeks. The UI looks tight. Buttons glow just right, hover states are smooth, and the animations flow like that cold yoghurt I mentioned earlier. You click through the flows — login, dashboard, a few form submissions — everything feels buttery. You nod to yourself. \"Solid,\" you think. \"Safe.\"",[16,1574,1575],{},"But safety, it turns out, is often a feeling, not a fact.",[16,1577,1578],{},"You feel safe because you used the app the way it was supposed to be used. But apps live in the wild, and in the wild, people don't follow scripts. They mistype. They reload mid-request. They submit empty forms. Some dig deeper — inspect elements, open DevTools, and start sending all sorts of unexpected things to your server. And then there are the clever ones. The folks who skip your UI entirely and go straight for the real prize: your server actions.",[16,1580,1581],{},"They send direct fetch requests. They guess routes. They trigger functions that were never meant for them. No UI. No animation. No questions asked.",[16,1583,1584],{},"And if your server isn't ready — if it doesn't pause for a moment and ask, \"Wait, should I be doing this?\" — then it just responds. No checks, no guards, no sanity.",[16,1586,1587],{},"That's how a clean app becomes a loud liability.",[16,1589,1590],{},"The polish on your frontend doesn't matter if the logic underneath is just blurting things out. Your backend starts oversharing. Suddenly, a random user is deleting data they shouldn't even see. Or creating records. Or accessing private information. Not because they broke in, but because you left the door wide open.",[16,1592,1593],{},"It's like leaving your diary on a park bench and wondering why someone read it.",[16,1595,1596],{},"And you pay for it — literally. You start seeing inflated bills from background jobs gone rogue. Logs overflowing with nonsense. Your database filled with junk entries. Worst of all, you lose credibility. People stop trusting the product. Not because it looks bad — but because it couldn't stay quiet when it mattered.",[16,1598,1599],{},"That's the danger of a backend that doesn't lock in. One that just keeps yapping.",[16,1601,1602],{},"Look, it's okay to talk. It's okay to open up. But solid words — intentional words — carry more weight than a flurry of unfiltered noise. Even chefs say a cook that talks too much probably doesn't know how to cook. The same goes for apps. The ones that speak too freely often aren't built with care.",[16,1604,1605,1610],{},[54,1606,1609],{"href":1607,"rel":1608},"https:\u002F\u002Fnext-safe-action.dev\u002Fdocs\u002Fgetting-started",[58],"next-safe-action"," changes that.",[16,1612,1613],{},"It gives your app structure. It gives your server guardrails. Instead of instantly responding to any request, it gives you a clean pattern to validate intent, check for permissions, and control who gets to do what. It's like having a bouncer at the door of every server action, asking, \"Who sent you?\" before anything even happens.",[16,1615,1616],{},"Even better, it builds in a healthy pause. A moment of state — pending, success, error. That delay isn't just for UX polish. It's the space where you think, where the app confirms, \"Yes, I'm doing the right thing.\"",[16,1618,1619],{},"No blurting. No oversharing. Just clarity.",[16,1621,1622],{},"That's what locking in looks like.",[71,1624,1626],{"id":1625},"the-cost-of-silence-why-locking-in-is-the-smart-move","The Cost of Silence: Why Locking In Is the Smart Move",[16,1628,1629],{},"So, we've established that oversharing in code can break your app. But let's dig deeper into what happens when your server finally locks in.",[16,1631,1632],{},"Imagine you're hosting a party. You've got the guest list covered — friends, coworkers, everyone you trust. The atmosphere is relaxed, the conversation is flowing, and the vibe is great. But then, someone unexpected shows up. No invite. They don't know the rules. They walk right in, help themselves to the snacks, and sit down on the couch without even saying hello.",[16,1634,1635],{},"At first, it's not a big deal. They're quiet. They blend in. But over time, things start to shift. People begin noticing. Conversations stop. You start hearing whispers. Who is this person? Why are they here? What are they doing?",[16,1637,1638],{},"That's what unfiltered access does to your server. It opens the door for random, unvalidated requests to come in. Initially, it might seem harmless. But over time, those unknown requests stack up. They start to shift your app's behavior, compromise its security, and eat away at its credibility.",[16,1640,1641,1642,1644],{},"And this is where ",[66,1643,1609],{}," comes in.",[16,1646,1647],{},"Next-safe-action is like the velvet rope at the door, carefully managing who gets in and when. It ensures only trusted actions are allowed to pass through. This is about creating a safe environment — not to be rude, but to establish the trust your app needs to thrive.",[16,1649,1650,1651,1653],{},"When you lock in your server actions with ",[66,1652,1609],{},", it gives your app a sense of order and control. Here's what it does:",[96,1655,1656,1662,1668],{},[99,1657,1658,1661],{},[66,1659,1660],{},"Type Safety",": Every input is validated. Your server knows exactly what to expect. No more garbage data sneaking through.",[99,1663,1664,1667],{},[66,1665,1666],{},"Zod-Powered Validation",": It checks the validity of data before letting it through, ensuring users can't send malicious or malformed data.",[99,1669,1670,1673],{},[66,1671,1672],{},"Server-Side Control",": Actions are only triggered from the client where you explicitly allow them, giving you full control over who can do what.",[16,1675,1676,1677,1679],{},"Think of it like this: ",[66,1678,1609],{}," doesn't just put a filter on your server; it teaches it how to think. It's like your server now knows when to pause and ask, \"Wait, am I doing this correctly?\" before responding. It's about creating that feedback loop that helps both you and your app stay on track.",[16,1681,1682],{},"When your server locks in, it doesn't just protect data — it safeguards the entire user experience. With that extra layer of thought, it doesn't get overwhelmed by random requests or sloppy inputs. The system doesn't buckle. It responds predictably, and it's safe.",[16,1684,1685,1686,1688],{},"And here's the bonus: locking in with ",[66,1687,1609],{}," means less processing power wasted on rogue requests. No unnecessary retries. No timeouts. You'll start seeing fewer bills because your server isn't spinning its wheels on unwanted or invalid actions.",[16,1690,1691,1692,1695],{},"It's like a chef in a kitchen. They don't throw everything in the pot hoping it'll taste good. They know exactly what ingredients are needed, when they're needed, and how much to use. ",[66,1693,1694],{},"Next-safe-action"," does the same for your server. It makes sure the actions are clear, well-defined, and executed with care.",[16,1697,1698,1700],{},[66,1699,1694],{}," is more than just a safeguard against attackers. It's about ensuring your app doesn't make mistakes out of eagerness. It doesn't overshare. It doesn't act recklessly. It only does exactly what it's meant to do — and only when it's supposed to.",[16,1702,1703],{},"This level of control builds trust. When users know they're interacting with an app that's not going to overshare, they'll use it more. They'll trust it more. And that's the kind of app users keep coming back to.",[71,1705,1707],{"id":1706},"enough-talk-lets-lock-in","Enough Talk, Let's Lock In",[16,1709,1710],{},"Alright, we've set the scene. We've talked about the risks, the consequences, and the need for locking in. But how do you actually get started? Simple.",[11,1712,1714],{"id":1713},"step-1-install-the-dependencies","Step 1: Install the Dependencies",[16,1716,1717,1718],{},"You're just one command away from protecting your server with ",[66,1719,1720],{},"next-safe-action:",[145,1722,1724],{"className":147,"code":1723,"language":149,"meta":21,"style":21},"pnpm add next-safe-action zod\n",[151,1725,1726],{"__ignoreMap":21},[103,1727,1728,1731,1734,1737],{"class":155,"line":156},[103,1729,1730],{"class":159},"pnpm",[103,1732,1733],{"class":163}," add",[103,1735,1736],{"class":163}," next-safe-action",[103,1738,1739],{"class":163}," zod\n",[11,1741,1743],{"id":1742},"why-zod","Why Zod?",[16,1745,1746,1747,1750,1751,1753],{},"Why ",[66,1748,1749],{},"Zod","? Because it's a powerful, type-safe validation library that works great with TypeScript and integrates seamlessly with ",[66,1752,1609],{},". It ensures your inputs are validated correctly before any action is executed.",[16,1755,1756,1757,1759,1760,1767,1768,1771,1772,1775,1776,1778],{},"But hey, I get it — everyone has their own preferences. If you're more comfortable with another validation library, feel free to swap out ",[66,1758,1749],{},". You could try ",[54,1761,1764],{"href":1762,"rel":1763},"https:\u002F\u002Fvalibot.dev\u002F",[58],[66,1765,1766],{},"Valibot"," (a fresh, up-and-coming option), ",[66,1769,1770],{},"Yup",", or ",[66,1773,1774],{},"TypeBox",". The choice is yours, but ",[66,1777,1749],{}," is a personal favorite for type safety.",[11,1780,1782],{"id":1781},"step-2-define-safe-actions","Step 2: Define Safe Actions",[16,1784,1785],{},"Once you've installed the necessary packages, you can start defining your server actions with safety in mind.",[16,1787,1788,1789,338],{},"Here's a basic example of how you might set up a server action with ",[66,1790,1609],{},[145,1792,1794],{"className":285,"code":1793,"language":287,"meta":21,"style":21},"import {\n  DEFAULT_SERVER_ERROR_MESSAGE,\n  createSafeActionClient,\n} from \"next-safe-action\";\n\n\u002F\u002F Base client with error handling and middleware\nexport const actionClient = createSafeActionClient({\n  handleServerError(e: Error | { errors?: Record\u003Cstring, string> }) {\n    console.error(\"Action error:\", e.message);\n\n    if (e instanceof Error) {\n      return e.message;\n    }\n\n    return DEFAULT_SERVER_ERROR_MESSAGE;\n  },\n}).use(async ({ next }) => {\n  const result = await next();\n  return result;\n});\n",[151,1795,1796,1802,1807,1812,1823,1827,1832,1848,1891,1907,1911,1927,1935,1940,1944,1954,1959,1982,1998,2005],{"__ignoreMap":21},[103,1797,1798,1800],{"class":155,"line":156},[103,1799,295],{"class":294},[103,1801,656],{"class":219},[103,1803,1804],{"class":155,"line":223},[103,1805,1806],{"class":219},"  DEFAULT_SERVER_ERROR_MESSAGE,\n",[103,1808,1809],{"class":155,"line":233},[103,1810,1811],{"class":219},"  createSafeActionClient,\n",[103,1813,1814,1816,1818,1821],{"class":155,"line":248},[103,1815,576],{"class":219},[103,1817,301],{"class":294},[103,1819,1820],{"class":163}," \"next-safe-action\"",[103,1822,307],{"class":219},[103,1824,1825],{"class":155,"line":259},[103,1826,327],{"emptyLinePlaceholder":326},[103,1828,1829],{"class":155,"line":265},[103,1830,1831],{"class":449},"\u002F\u002F Base client with error handling and middleware\n",[103,1833,1834,1836,1838,1841,1843,1846],{"class":155,"line":475},[103,1835,367],{"class":294},[103,1837,433],{"class":294},[103,1839,1840],{"class":226}," actionClient",[103,1842,344],{"class":294},[103,1844,1845],{"class":159}," createSafeActionClient",[103,1847,444],{"class":219},[103,1849,1850,1853,1855,1858,1860,1863,1866,1869,1872,1875,1878,1881,1884,1886,1888],{"class":155,"line":480},[103,1851,1852],{"class":159},"  handleServerError",[103,1854,756],{"class":219},[103,1856,1857],{"class":765},"e",[103,1859,338],{"class":294},[103,1861,1862],{"class":159}," Error",[103,1864,1865],{"class":294}," |",[103,1867,1868],{"class":219}," { ",[103,1870,1871],{"class":765},"errors",[103,1873,1874],{"class":294},"?:",[103,1876,1877],{"class":159}," Record",[103,1879,1880],{"class":219},"\u003C",[103,1882,1883],{"class":226},"string",[103,1885,461],{"class":219},[103,1887,1883],{"class":226},[103,1889,1890],{"class":219},"> }) {\n",[103,1892,1893,1896,1899,1901,1904],{"class":155,"line":486},[103,1894,1895],{"class":219},"    console.",[103,1897,1898],{"class":159},"error",[103,1900,756],{"class":219},[103,1902,1903],{"class":163},"\"Action error:\"",[103,1905,1906],{"class":219},", e.message);\n",[103,1908,1909],{"class":155,"line":495},[103,1910,327],{"emptyLinePlaceholder":326},[103,1912,1913,1916,1919,1922,1924],{"class":155,"line":851},[103,1914,1915],{"class":294},"    if",[103,1917,1918],{"class":219}," (e ",[103,1920,1921],{"class":294},"instanceof",[103,1923,1862],{"class":159},[103,1925,1926],{"class":219},") {\n",[103,1928,1929,1932],{"class":155,"line":857},[103,1930,1931],{"class":294},"      return",[103,1933,1934],{"class":219}," e.message;\n",[103,1936,1937],{"class":155,"line":862},[103,1938,1939],{"class":219},"    }\n",[103,1941,1942],{"class":155,"line":870},[103,1943,327],{"emptyLinePlaceholder":326},[103,1945,1946,1949,1952],{"class":155,"line":876},[103,1947,1948],{"class":294},"    return",[103,1950,1951],{"class":226}," DEFAULT_SERVER_ERROR_MESSAGE",[103,1953,307],{"class":219},[103,1955,1956],{"class":155,"line":901},[103,1957,1958],{"class":219},"  },\n",[103,1960,1961,1964,1967,1969,1971,1973,1976,1978,1980],{"class":155,"line":907},[103,1962,1963],{"class":219},"}).",[103,1965,1966],{"class":159},"use",[103,1968,756],{"class":219},[103,1970,759],{"class":294},[103,1972,762],{"class":219},[103,1974,1975],{"class":765},"next",[103,1977,769],{"class":219},[103,1979,772],{"class":294},[103,1981,656],{"class":219},[103,1983,1984,1986,1989,1991,1993,1996],{"class":155,"line":1106},[103,1985,1060],{"class":294},[103,1987,1988],{"class":226}," result",[103,1990,344],{"class":294},[103,1992,793],{"class":294},[103,1994,1995],{"class":159}," next",[103,1997,362],{"class":219},[103,1999,2000,2002],{"class":155,"line":1115},[103,2001,1109],{"class":294},[103,2003,2004],{"class":219}," result;\n",[103,2006,2007],{"class":155,"line":1133},[103,2008,498],{"class":219},[11,2010,2012],{"id":2011},"step-3-write-your-first-safe-action","Step 3: Write Your First Safe Action",[16,2014,2015],{},"Now let's put it to use.",[16,2017,2018,2019,2022],{},"Here's an example of a ",[66,2020,2021],{},"resend email verification"," action. We validate the input, send a request to the backend, and handle any errors cleanly — all while staying type-safe and guarded.",[145,2024,2026],{"className":285,"code":2025,"language":287,"meta":21,"style":21},"\"use server\";\n\nimport { z } from \"zod\";\nimport axios from \"axios\";\nimport { actionClient } from \"@\u002Flib\u002Fintegrations\u002Fsafe-action\";\nimport axiosInstance from \"@\u002Flib\u002Fintegrations\u002Faxios-wrapper\";\n\n\u002F\u002F Validation schema\nconst confirmEmailSchema = z.object({\n  email: z.string().email(),\n});\n\n\u002F\u002F action\nexport const resendVerification = actionClient\n  .schema(confirmEmailSchema)\n  .action(async ({ parsedInput }) => {\n    const { email } = parsedInput;\n\n    try {\n      await axiosInstance.post(\"\u002Fauth\u002Fsend_verification\", { email });\n\n      return {\n        success: true,\n        message: \"Please check your email for a verification link\",\n      };\n    } catch (error) {\n      if (axios.isAxiosError(error) && error.response?.data?.message) {\n        throw new Error(error.response.data.message);\n      }\n\n      throw new Error(\"Something went wrong. Please try again later.\");\n    }\n  });\n",[151,2027,2028,2035,2039,2053,2067,2081,2095,2099,2104,2121,2137,2141,2145,2150,2164,2175,2197,2214,2218,2225,2244,2248,2254,2264,2274,2279,2291,2312,2326,2332,2337,2354,2359],{"__ignoreMap":21},[103,2029,2030,2033],{"class":155,"line":156},[103,2031,2032],{"class":163},"\"use server\"",[103,2034,307],{"class":219},[103,2036,2037],{"class":155,"line":223},[103,2038,327],{"emptyLinePlaceholder":326},[103,2040,2041,2043,2046,2048,2051],{"class":155,"line":233},[103,2042,295],{"class":294},[103,2044,2045],{"class":219}," { z } ",[103,2047,301],{"class":294},[103,2049,2050],{"class":163}," \"zod\"",[103,2052,307],{"class":219},[103,2054,2055,2057,2060,2062,2065],{"class":155,"line":248},[103,2056,295],{"class":294},[103,2058,2059],{"class":219}," axios ",[103,2061,301],{"class":294},[103,2063,2064],{"class":163}," \"axios\"",[103,2066,307],{"class":219},[103,2068,2069,2071,2074,2076,2079],{"class":155,"line":259},[103,2070,295],{"class":294},[103,2072,2073],{"class":219}," { actionClient } ",[103,2075,301],{"class":294},[103,2077,2078],{"class":163}," \"@\u002Flib\u002Fintegrations\u002Fsafe-action\"",[103,2080,307],{"class":219},[103,2082,2083,2085,2088,2090,2093],{"class":155,"line":265},[103,2084,295],{"class":294},[103,2086,2087],{"class":219}," axiosInstance ",[103,2089,301],{"class":294},[103,2091,2092],{"class":163}," \"@\u002Flib\u002Fintegrations\u002Faxios-wrapper\"",[103,2094,307],{"class":219},[103,2096,2097],{"class":155,"line":475},[103,2098,327],{"emptyLinePlaceholder":326},[103,2100,2101],{"class":155,"line":480},[103,2102,2103],{"class":449},"\u002F\u002F Validation schema\n",[103,2105,2106,2108,2111,2113,2116,2119],{"class":155,"line":486},[103,2107,332],{"class":294},[103,2109,2110],{"class":226}," confirmEmailSchema",[103,2112,344],{"class":294},[103,2114,2115],{"class":219}," z.",[103,2117,2118],{"class":159},"object",[103,2120,444],{"class":219},[103,2122,2123,2126,2128,2131,2134],{"class":155,"line":495},[103,2124,2125],{"class":219},"  email: z.",[103,2127,1883],{"class":159},[103,2129,2130],{"class":219},"().",[103,2132,2133],{"class":159},"email",[103,2135,2136],{"class":219},"(),\n",[103,2138,2139],{"class":155,"line":851},[103,2140,498],{"class":219},[103,2142,2143],{"class":155,"line":857},[103,2144,327],{"emptyLinePlaceholder":326},[103,2146,2147],{"class":155,"line":862},[103,2148,2149],{"class":449},"\u002F\u002F action\n",[103,2151,2152,2154,2156,2159,2161],{"class":155,"line":870},[103,2153,367],{"class":294},[103,2155,433],{"class":294},[103,2157,2158],{"class":226}," resendVerification",[103,2160,344],{"class":294},[103,2162,2163],{"class":219}," actionClient\n",[103,2165,2166,2169,2172],{"class":155,"line":876},[103,2167,2168],{"class":219},"  .",[103,2170,2171],{"class":159},"schema",[103,2173,2174],{"class":219},"(confirmEmailSchema)\n",[103,2176,2177,2179,2182,2184,2186,2188,2191,2193,2195],{"class":155,"line":901},[103,2178,2168],{"class":219},[103,2180,2181],{"class":159},"action",[103,2183,756],{"class":219},[103,2185,759],{"class":294},[103,2187,762],{"class":219},[103,2189,2190],{"class":765},"parsedInput",[103,2192,769],{"class":219},[103,2194,772],{"class":294},[103,2196,656],{"class":219},[103,2198,2199,2202,2204,2206,2209,2211],{"class":155,"line":907},[103,2200,2201],{"class":294},"    const",[103,2203,1868],{"class":219},[103,2205,2133],{"class":226},[103,2207,2208],{"class":219}," } ",[103,2210,790],{"class":294},[103,2212,2213],{"class":219}," parsedInput;\n",[103,2215,2216],{"class":155,"line":1106},[103,2217,327],{"emptyLinePlaceholder":326},[103,2219,2220,2223],{"class":155,"line":1115},[103,2221,2222],{"class":294},"    try",[103,2224,656],{"class":219},[103,2226,2227,2230,2233,2236,2238,2241],{"class":155,"line":1133},[103,2228,2229],{"class":294},"      await",[103,2231,2232],{"class":219}," axiosInstance.",[103,2234,2235],{"class":159},"post",[103,2237,756],{"class":219},[103,2239,2240],{"class":163},"\"\u002Fauth\u002Fsend_verification\"",[103,2242,2243],{"class":219},", { email });\n",[103,2245,2246],{"class":155,"line":1145},[103,2247,327],{"emptyLinePlaceholder":326},[103,2249,2250,2252],{"class":155,"line":1161},[103,2251,1931],{"class":294},[103,2253,656],{"class":219},[103,2255,2256,2259,2262],{"class":155,"line":1171},[103,2257,2258],{"class":219},"        success: ",[103,2260,2261],{"class":226},"true",[103,2263,245],{"class":219},[103,2265,2266,2269,2272],{"class":155,"line":1181},[103,2267,2268],{"class":219},"        message: ",[103,2270,2271],{"class":163},"\"Please check your email for a verification link\"",[103,2273,245],{"class":219},[103,2275,2276],{"class":155,"line":1187},[103,2277,2278],{"class":219},"      };\n",[103,2280,2282,2285,2288],{"class":155,"line":2281},26,[103,2283,2284],{"class":219},"    } ",[103,2286,2287],{"class":294},"catch",[103,2289,2290],{"class":219}," (error) {\n",[103,2292,2294,2297,2300,2303,2306,2309],{"class":155,"line":2293},27,[103,2295,2296],{"class":294},"      if",[103,2298,2299],{"class":219}," (axios.",[103,2301,2302],{"class":159},"isAxiosError",[103,2304,2305],{"class":219},"(error) ",[103,2307,2308],{"class":294},"&&",[103,2310,2311],{"class":219}," error.response?.data?.message) {\n",[103,2313,2315,2318,2321,2323],{"class":155,"line":2314},28,[103,2316,2317],{"class":294},"        throw",[103,2319,2320],{"class":294}," new",[103,2322,1862],{"class":159},[103,2324,2325],{"class":219},"(error.response.data.message);\n",[103,2327,2329],{"class":155,"line":2328},29,[103,2330,2331],{"class":219},"      }\n",[103,2333,2335],{"class":155,"line":2334},30,[103,2336,327],{"emptyLinePlaceholder":326},[103,2338,2340,2343,2345,2347,2349,2352],{"class":155,"line":2339},31,[103,2341,2342],{"class":294},"      throw",[103,2344,2320],{"class":294},[103,2346,1862],{"class":159},[103,2348,756],{"class":219},[103,2350,2351],{"class":163},"\"Something went wrong. Please try again later.\"",[103,2353,1271],{"class":219},[103,2355,2357],{"class":155,"line":2356},32,[103,2358,1939],{"class":219},[103,2360,2362],{"class":155,"line":2361},33,[103,2363,2364],{"class":219},"  });\n",[16,2366,2367,2368,2371,2372,2375,2376,69],{},"And that's it. Simple, clean, and secure — your server no longer just responds to anything. It ",[30,2369,2370],{},"thinks",", it ",[30,2373,2374],{},"filters",", and it ",[30,2377,2378],{},"locks in",[16,2380,2381,2382,2385,2386,2388,2389,2392,2393,2396],{},"To use this on the client, you simply define the user interface. While you ",[30,2383,2384],{},"could"," call the server action directly, ",[66,2387,1609],{}," also exposes a special hook for the client: ",[151,2390,2391],{},"useAction",". It's built not just for calling actions, but for listening, thinking, and responding. Think of it like a conversation—",[66,2394,2395],{},"pause, process, then speak",". That's the pattern.",[145,2398,2400],{"className":919,"code":2399,"language":921,"meta":21,"style":21},"\"use client\";\n\nimport { Button } from \"@\u002Fcomponents\u002Fui\u002Fbutton\";\nimport { DEFAULT_SERVER_ERROR_MESSAGE } from \"next-safe-action\";\nimport { useAction } from \"next-safe-action\u002Fhooks\";\nimport { useQueryState } from \"nuqs\";\nimport { toast } from \"sonner\";\nimport { resendVerification } from \"..\u002F_actions\";\nimport { useCountdown } from \"..\u002F_hooks\";\nimport { referralQueryParsers, referralTypeEnums } from \"..\u002F_schema\";\n\nconst RESEND_COUNTDOWN_SECONDS = 60;\n\nexport const ResendConfirmation = ({ email }: { email: string }) => {\n  const { countdown, startCountdown, isActive } = useCountdown(\n    RESEND_COUNTDOWN_SECONDS,\n  );\n  const [referral] = useQueryState(\"referral\", referralQueryParsers.referral);\n\n  const { execute, status } = useAction(resendVerification, {\n    onSuccess: (data) => {\n      toast.success(\n        data.data?.message || \"Verification email sent successfully\",\n      );\n    },\n    onError: (error) => {\n      toast.error(error.error.serverError);\n    },\n  });\n\n  const handleResend = async () => {\n    startCountdown();\n    execute({ email });\n  };\n\n  return (\n    \u003C>\n      {referral === referralTypeEnums.Enum[\"sign-up\"] ? (\n        \u003Cdiv className=\"mt-2 text-sm\">\n          Did not receive an email?{\" \"}\n          \u003CButton\n            className=\"p-0 text-blue-600 disabled:text-gray-400\"\n            onClick={handleResend}\n            disabled={isActive || status === \"executing\"}\n            variant=\"link\"\n          >\n            {isActive\n              ? `Wait ${countdown} seconds to resend`\n              : \"Click to resend\"}\n          \u003C\u002FButton>\n        \u003C\u002Fdiv>\n      ) : (\n        \u003CButton\n          onClick={handleResend}\n          className=\"w-full border border-blue-600 text-blue-600 bg-white\"\n          disabled={isActive || status === \"executing\"}\n        >\n          {isActive\n            ? `Wait ${countdown} seconds to resend`\n            : \"Request Verification\"}\n        \u003C\u002FButton>\n      )}\n    \u003C\u002F>\n  );\n};\n",[151,2401,2402,2409,2413,2427,2440,2454,2468,2482,2496,2510,2524,2528,2542,2546,2580,2609,2616,2620,2646,2650,2674,2692,2702,2714,2719,2724,2739,2748,2752,2756,2760,2778,2785,2793,2799,2804,2811,2817,2839,2856,2867,2876,2887,2898,2921,2932,2938,2944,2958,2969,2980,2990,3000,3007,3017,3028,3048,3054,3060,3072,3083,3092,3098,3104,3109],{"__ignoreMap":21},[103,2403,2404,2407],{"class":155,"line":156},[103,2405,2406],{"class":163},"\"use client\"",[103,2408,307],{"class":219},[103,2410,2411],{"class":155,"line":223},[103,2412,327],{"emptyLinePlaceholder":326},[103,2414,2415,2417,2420,2422,2425],{"class":155,"line":233},[103,2416,295],{"class":294},[103,2418,2419],{"class":219}," { Button } ",[103,2421,301],{"class":294},[103,2423,2424],{"class":163}," \"@\u002Fcomponents\u002Fui\u002Fbutton\"",[103,2426,307],{"class":219},[103,2428,2429,2431,2434,2436,2438],{"class":155,"line":248},[103,2430,295],{"class":294},[103,2432,2433],{"class":219}," { DEFAULT_SERVER_ERROR_MESSAGE } ",[103,2435,301],{"class":294},[103,2437,1820],{"class":163},[103,2439,307],{"class":219},[103,2441,2442,2444,2447,2449,2452],{"class":155,"line":259},[103,2443,295],{"class":294},[103,2445,2446],{"class":219}," { useAction } ",[103,2448,301],{"class":294},[103,2450,2451],{"class":163}," \"next-safe-action\u002Fhooks\"",[103,2453,307],{"class":219},[103,2455,2456,2458,2461,2463,2466],{"class":155,"line":265},[103,2457,295],{"class":294},[103,2459,2460],{"class":219}," { useQueryState } ",[103,2462,301],{"class":294},[103,2464,2465],{"class":163}," \"nuqs\"",[103,2467,307],{"class":219},[103,2469,2470,2472,2475,2477,2480],{"class":155,"line":475},[103,2471,295],{"class":294},[103,2473,2474],{"class":219}," { toast } ",[103,2476,301],{"class":294},[103,2478,2479],{"class":163}," \"sonner\"",[103,2481,307],{"class":219},[103,2483,2484,2486,2489,2491,2494],{"class":155,"line":480},[103,2485,295],{"class":294},[103,2487,2488],{"class":219}," { resendVerification } ",[103,2490,301],{"class":294},[103,2492,2493],{"class":163}," \"..\u002F_actions\"",[103,2495,307],{"class":219},[103,2497,2498,2500,2503,2505,2508],{"class":155,"line":486},[103,2499,295],{"class":294},[103,2501,2502],{"class":219}," { useCountdown } ",[103,2504,301],{"class":294},[103,2506,2507],{"class":163}," \"..\u002F_hooks\"",[103,2509,307],{"class":219},[103,2511,2512,2514,2517,2519,2522],{"class":155,"line":495},[103,2513,295],{"class":294},[103,2515,2516],{"class":219}," { referralQueryParsers, referralTypeEnums } ",[103,2518,301],{"class":294},[103,2520,2521],{"class":163}," \"..\u002F_schema\"",[103,2523,307],{"class":219},[103,2525,2526],{"class":155,"line":851},[103,2527,327],{"emptyLinePlaceholder":326},[103,2529,2530,2532,2535,2537,2540],{"class":155,"line":857},[103,2531,332],{"class":294},[103,2533,2534],{"class":226}," RESEND_COUNTDOWN_SECONDS",[103,2536,344],{"class":294},[103,2538,2539],{"class":226}," 60",[103,2541,307],{"class":219},[103,2543,2544],{"class":155,"line":862},[103,2545,327],{"emptyLinePlaceholder":326},[103,2547,2548,2550,2552,2555,2557,2559,2561,2564,2566,2568,2570,2572,2574,2576,2578],{"class":155,"line":870},[103,2549,367],{"class":294},[103,2551,433],{"class":294},[103,2553,2554],{"class":159}," ResendConfirmation",[103,2556,344],{"class":294},[103,2558,762],{"class":219},[103,2560,2133],{"class":765},[103,2562,2563],{"class":219}," }",[103,2565,338],{"class":294},[103,2567,1868],{"class":219},[103,2569,2133],{"class":765},[103,2571,338],{"class":294},[103,2573,1042],{"class":226},[103,2575,769],{"class":219},[103,2577,772],{"class":294},[103,2579,656],{"class":219},[103,2581,2582,2584,2586,2589,2591,2594,2596,2599,2601,2603,2606],{"class":155,"line":876},[103,2583,1060],{"class":294},[103,2585,1868],{"class":219},[103,2587,2588],{"class":226},"countdown",[103,2590,461],{"class":219},[103,2592,2593],{"class":226},"startCountdown",[103,2595,461],{"class":219},[103,2597,2598],{"class":226},"isActive",[103,2600,2208],{"class":219},[103,2602,790],{"class":294},[103,2604,2605],{"class":159}," useCountdown",[103,2607,2608],{"class":219},"(\n",[103,2610,2611,2614],{"class":155,"line":901},[103,2612,2613],{"class":226},"    RESEND_COUNTDOWN_SECONDS",[103,2615,245],{"class":219},[103,2617,2618],{"class":155,"line":907},[103,2619,1184],{"class":219},[103,2621,2622,2624,2627,2630,2633,2635,2638,2640,2643],{"class":155,"line":1106},[103,2623,1060],{"class":294},[103,2625,2626],{"class":219}," [",[103,2628,2629],{"class":226},"referral",[103,2631,2632],{"class":219},"] ",[103,2634,790],{"class":294},[103,2636,2637],{"class":159}," useQueryState",[103,2639,756],{"class":219},[103,2641,2642],{"class":163},"\"referral\"",[103,2644,2645],{"class":219},", referralQueryParsers.referral);\n",[103,2647,2648],{"class":155,"line":1115},[103,2649,327],{"emptyLinePlaceholder":326},[103,2651,2652,2654,2656,2659,2661,2664,2666,2668,2671],{"class":155,"line":1133},[103,2653,1060],{"class":294},[103,2655,1868],{"class":219},[103,2657,2658],{"class":226},"execute",[103,2660,461],{"class":219},[103,2662,2663],{"class":226},"status",[103,2665,2208],{"class":219},[103,2667,790],{"class":294},[103,2669,2670],{"class":159}," useAction",[103,2672,2673],{"class":219},"(resendVerification, {\n",[103,2675,2676,2679,2682,2685,2688,2690],{"class":155,"line":1145},[103,2677,2678],{"class":159},"    onSuccess",[103,2680,2681],{"class":219},": (",[103,2683,2684],{"class":765},"data",[103,2686,2687],{"class":219},") ",[103,2689,772],{"class":294},[103,2691,656],{"class":219},[103,2693,2694,2697,2700],{"class":155,"line":1161},[103,2695,2696],{"class":219},"      toast.",[103,2698,2699],{"class":159},"success",[103,2701,2608],{"class":219},[103,2703,2704,2707,2709,2712],{"class":155,"line":1171},[103,2705,2706],{"class":219},"        data.data?.message ",[103,2708,817],{"class":294},[103,2710,2711],{"class":163}," \"Verification email sent successfully\"",[103,2713,245],{"class":219},[103,2715,2716],{"class":155,"line":1181},[103,2717,2718],{"class":219},"      );\n",[103,2720,2721],{"class":155,"line":1187},[103,2722,2723],{"class":219},"    },\n",[103,2725,2726,2729,2731,2733,2735,2737],{"class":155,"line":2281},[103,2727,2728],{"class":159},"    onError",[103,2730,2681],{"class":219},[103,2732,1898],{"class":765},[103,2734,2687],{"class":219},[103,2736,772],{"class":294},[103,2738,656],{"class":219},[103,2740,2741,2743,2745],{"class":155,"line":2293},[103,2742,2696],{"class":219},[103,2744,1898],{"class":159},[103,2746,2747],{"class":219},"(error.error.serverError);\n",[103,2749,2750],{"class":155,"line":2314},[103,2751,2723],{"class":219},[103,2753,2754],{"class":155,"line":2328},[103,2755,2364],{"class":219},[103,2757,2758],{"class":155,"line":2334},[103,2759,327],{"emptyLinePlaceholder":326},[103,2761,2762,2764,2767,2769,2771,2774,2776],{"class":155,"line":2339},[103,2763,1060],{"class":294},[103,2765,2766],{"class":159}," handleResend",[103,2768,344],{"class":294},[103,2770,977],{"class":294},[103,2772,2773],{"class":219}," () ",[103,2775,772],{"class":294},[103,2777,656],{"class":219},[103,2779,2780,2783],{"class":155,"line":2356},[103,2781,2782],{"class":159},"    startCountdown",[103,2784,362],{"class":219},[103,2786,2787,2790],{"class":155,"line":2361},[103,2788,2789],{"class":159},"    execute",[103,2791,2792],{"class":219},"({ email });\n",[103,2794,2796],{"class":155,"line":2795},34,[103,2797,2798],{"class":219},"  };\n",[103,2800,2802],{"class":155,"line":2801},35,[103,2803,327],{"emptyLinePlaceholder":326},[103,2805,2807,2809],{"class":155,"line":2806},36,[103,2808,1109],{"class":294},[103,2810,1112],{"class":219},[103,2812,2814],{"class":155,"line":2813},37,[103,2815,2816],{"class":219},"    \u003C>\n",[103,2818,2820,2823,2826,2829,2832,2834,2837],{"class":155,"line":2819},38,[103,2821,2822],{"class":219},"      {referral ",[103,2824,2825],{"class":294},"===",[103,2827,2828],{"class":219}," referralTypeEnums.Enum[",[103,2830,2831],{"class":163},"\"sign-up\"",[103,2833,2632],{"class":219},[103,2835,2836],{"class":294},"?",[103,2838,1112],{"class":219},[103,2840,2842,2844,2846,2849,2851,2854],{"class":155,"line":2841},39,[103,2843,1148],{"class":219},[103,2845,1284],{"class":1121},[103,2847,2848],{"class":159}," className",[103,2850,790],{"class":294},[103,2852,2853],{"class":163},"\"mt-2 text-sm\"",[103,2855,1142],{"class":219},[103,2857,2859,2862,2865],{"class":155,"line":2858},40,[103,2860,2861],{"class":219},"          Did not receive an email?{",[103,2863,2864],{"class":163},"\" \"",[103,2866,268],{"class":219},[103,2868,2870,2873],{"class":155,"line":2869},41,[103,2871,2872],{"class":219},"          \u003C",[103,2874,2875],{"class":226},"Button\n",[103,2877,2879,2882,2884],{"class":155,"line":2878},42,[103,2880,2881],{"class":159},"            className",[103,2883,790],{"class":294},[103,2885,2886],{"class":163},"\"p-0 text-blue-600 disabled:text-gray-400\"\n",[103,2888,2890,2893,2895],{"class":155,"line":2889},43,[103,2891,2892],{"class":159},"            onClick",[103,2894,790],{"class":294},[103,2896,2897],{"class":219},"{handleResend}\n",[103,2899,2901,2904,2906,2909,2911,2914,2916,2919],{"class":155,"line":2900},44,[103,2902,2903],{"class":159},"            disabled",[103,2905,790],{"class":294},[103,2907,2908],{"class":219},"{isActive ",[103,2910,817],{"class":294},[103,2912,2913],{"class":219}," status ",[103,2915,2825],{"class":294},[103,2917,2918],{"class":163}," \"executing\"",[103,2920,268],{"class":219},[103,2922,2924,2927,2929],{"class":155,"line":2923},45,[103,2925,2926],{"class":159},"            variant",[103,2928,790],{"class":294},[103,2930,2931],{"class":163},"\"link\"\n",[103,2933,2935],{"class":155,"line":2934},46,[103,2936,2937],{"class":219},"          >\n",[103,2939,2941],{"class":155,"line":2940},47,[103,2942,2943],{"class":219},"            {isActive\n",[103,2945,2947,2950,2953,2955],{"class":155,"line":2946},48,[103,2948,2949],{"class":294},"              ?",[103,2951,2952],{"class":163}," `Wait ${",[103,2954,2588],{"class":219},[103,2956,2957],{"class":163},"} seconds to resend`\n",[103,2959,2961,2964,2967],{"class":155,"line":2960},49,[103,2962,2963],{"class":294},"              :",[103,2965,2966],{"class":163}," \"Click to resend\"",[103,2968,268],{"class":219},[103,2970,2972,2975,2978],{"class":155,"line":2971},50,[103,2973,2974],{"class":219},"          \u003C\u002F",[103,2976,2977],{"class":226},"Button",[103,2979,1142],{"class":219},[103,2981,2983,2986,2988],{"class":155,"line":2982},51,[103,2984,2985],{"class":219},"        \u003C\u002F",[103,2987,1284],{"class":1121},[103,2989,1142],{"class":219},[103,2991,2993,2996,2998],{"class":155,"line":2992},52,[103,2994,2995],{"class":219},"      ) ",[103,2997,338],{"class":294},[103,2999,1112],{"class":219},[103,3001,3003,3005],{"class":155,"line":3002},53,[103,3004,1148],{"class":219},[103,3006,2875],{"class":226},[103,3008,3010,3013,3015],{"class":155,"line":3009},54,[103,3011,3012],{"class":159},"          onClick",[103,3014,790],{"class":294},[103,3016,2897],{"class":219},[103,3018,3020,3023,3025],{"class":155,"line":3019},55,[103,3021,3022],{"class":159},"          className",[103,3024,790],{"class":294},[103,3026,3027],{"class":163},"\"w-full border border-blue-600 text-blue-600 bg-white\"\n",[103,3029,3031,3034,3036,3038,3040,3042,3044,3046],{"class":155,"line":3030},56,[103,3032,3033],{"class":159},"          disabled",[103,3035,790],{"class":294},[103,3037,2908],{"class":219},[103,3039,817],{"class":294},[103,3041,2913],{"class":219},[103,3043,2825],{"class":294},[103,3045,2918],{"class":163},[103,3047,268],{"class":219},[103,3049,3051],{"class":155,"line":3050},57,[103,3052,3053],{"class":219},"        >\n",[103,3055,3057],{"class":155,"line":3056},58,[103,3058,3059],{"class":219},"          {isActive\n",[103,3061,3063,3066,3068,3070],{"class":155,"line":3062},59,[103,3064,3065],{"class":294},"            ?",[103,3067,2952],{"class":163},[103,3069,2588],{"class":219},[103,3071,2957],{"class":163},[103,3073,3075,3078,3081],{"class":155,"line":3074},60,[103,3076,3077],{"class":294},"            :",[103,3079,3080],{"class":163}," \"Request Verification\"",[103,3082,268],{"class":219},[103,3084,3086,3088,3090],{"class":155,"line":3085},61,[103,3087,2985],{"class":219},[103,3089,2977],{"class":226},[103,3091,1142],{"class":219},[103,3093,3095],{"class":155,"line":3094},62,[103,3096,3097],{"class":219},"      )}\n",[103,3099,3101],{"class":155,"line":3100},63,[103,3102,3103],{"class":219},"    \u003C\u002F>\n",[103,3105,3107],{"class":155,"line":3106},64,[103,3108,1184],{"class":219},[103,3110,3112],{"class":155,"line":3111},65,[103,3113,677],{"class":219},[71,3115,3117],{"id":3116},"demo-video-see-it-in-action","Demo Video: See It In Action",[16,3119,3120,3121,3123],{},"Now that you've seen the code and understand how ",[66,3122,1609],{}," helps you protect your server actions, let's take a look at how it all comes together in real life. Watch the demo below to see how it works in the frontend — from sending a verification email, handling user interactions, to receiving real-time feedback.",[16,3125,3126],{},[19,3127],{"alt":21,"src":3128},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F1024\u002F1*fby0ebHnHsZIwym21s0dow.gif",[16,3130,3131],{},[30,3132,3133],{},"Demo showing the verification action performed",[16,3135,3136],{},[19,3137],{"alt":21,"src":3138},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F1024\u002F1*T4bYxWcbPAHn0F_d5FxzWQ.gif",[16,3140,3141],{},[30,3142,3143],{},"Demo showing the email verification process — in user mailbox",[71,3145,3147],{"id":3146},"final-thoughts-locking-in-like-you-mean-it","Final Thoughts: Locking In, Like You Mean It",[16,3149,3150],{},"So yeah, there you have it. From yapping without filters to finally learning how to pause, process, and speak with intention. Just like in life, the loudest server isn't the wisest. It's the one that knows when to hold back, when to validate, and when to act with purpose.",[16,3152,3153],{},"That's what next-safe-action gives you.",[16,3155,3156,3157,3160],{},"It's not just some fancy abstraction. It's a mindset shift. A way to make sure your server isn't just reacting, but ",[30,3158,3159],{},"thinking."," A way to build trust with your users because your app's not out here doing the most when nobody asked.",[16,3162,3163,3164,3167],{},"Whether it's sending verification emails or handling critical flows, you've now got the tools to move with confidence. You're no longer hoping your backend behaves — you ",[30,3165,3166],{},"know"," it will, because you locked it in.",[16,3169,3170,3171],{},"So next time you're building out that shiny new feature, remember:\nDon't just let your server yap.\nTeach it to listen. Teach it to think.\nAnd when it's ready — ",[66,3172,3173],{},"let it speak with purpose.",[16,3175,3176],{},[66,3177,3178],{},"Explore More, Tweak, Play:",[96,3180,3181,3190,3198,3207],{},[99,3182,3183,3184,3189],{},"🛠 ",[54,3185,3188],{"href":3186,"rel":3187},"https:\u002F\u002Fnext-safe-action-playground.vercel.app\u002F",[58],"Next Safe Action Playground"," — Try it out in real time. Break it. Fix it. Repeat.",[99,3191,3192,3193,3197],{},"📘 ",[54,3194,3196],{"href":1607,"rel":3195},[58],"Official Docs"," — Everything you need to know, from setup to best practices.",[99,3199,3200,3201,3206],{},"🧠 ",[54,3202,3205],{"href":3203,"rel":3204},"https:\u002F\u002Fgithub.com\u002FTheEdoRan\u002Fnext-safe-action",[58],"GitHub"," — Dive into the code, contribute, or just peep how it works under the hood.",[99,3208,3209,3210,3215],{},"🔐 Real-world example: ",[54,3211,3214],{"href":3212,"rel":3213},"https:\u002F\u002Fiq.wiki\u002F",[58],"IQ Wiki"," — The world's largest crypto encyclopedia, running safe and locked in.",[16,3217,3218,3219],{},"Happy building.\nAnd remember, ",[66,3220,3221],{},"talk less, lock in more.",[1479,3223,3224],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":21,"searchDepth":223,"depth":223,"links":3226},[3227,3228,3229,3235,3236],{"id":1565,"depth":223,"text":1566},{"id":1625,"depth":223,"text":1626},{"id":1706,"depth":223,"text":1707,"children":3230},[3231,3232,3233,3234],{"id":1713,"depth":233,"text":1714},{"id":1742,"depth":233,"text":1743},{"id":1781,"depth":233,"text":1782},{"id":2011,"depth":233,"text":2012},{"id":3116,"depth":223,"text":3117},{"id":3146,"depth":223,"text":3147},"https:\u002F\u002Fiamlope.medium.com\u002Fstop-yapping-lock-in-5e0a0673ab19","2025-04-25","Securing Next.js server actions with next-safe-action — typed input validation, Zod schemas, and clean error handling.",{},"\u002Fblog\u002Fstop-yapping-lock-in","9min",{"title":1515,"description":3239},"blog\u002Fstop-yapping-lock-in","tpq7xgyrRZMmP-NH51U09AFAIRz0fsFc3w_2645bF3g",{"id":3247,"title":3248,"body":3249,"canonical":5171,"date":5172,"description":5173,"draft":1504,"extension":1505,"lang":1506,"meta":5174,"navigation":326,"path":5175,"readingTime":5176,"seo":5177,"stem":5178,"__hash__":5179},"blog\u002Fblog\u002Fnuqs-because-urls-should-do-more.md","Nuqs: Because URLs Should Do More",{"type":8,"value":3250,"toc":5153},[3251,3255,3260,3263,3266,3269,3272,3277,3282,3287,3292,3297,3302,3307,3310,3313,3317,3320,3326,3332,3335,3341,3344,3347,3351,3354,3359,3366,3376,3383,3386,3397,3403,3407,3417,3420,3425,3432,3437,3441,3450,3457,3463,3466,3469,3474,3478,3481,3484,3488,3491,3531,3534,3538,3541,3544,3681,3684,3687,3691,3694,3697,3700,3703,4230,4234,4248,4256,4259,4262,4266,4269,4273,4276,4302,4306,4313,4430,4434,4437,5039,5042,5062,5066,5072,5078,5097,5112,5116,5123,5134,5144,5150],[11,3252,3254],{"id":3253},"move-beyond-local-state-go-beyond-plus-ultra","Move beyond local state — Go beyond, plus ultra.",[16,3256,3257],{},[19,3258],{"alt":21,"src":3259},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F665\u002F1*KUe2LG5cA3cR80GodnXW8A.jpeg",[16,3261,3262],{},"Valentine's Day. I had planned it down to perfection. The right place, the right atmosphere, the right seat — because ambiance matters, and I wanted this night to be unforgettable. I took my time picking the best spot, ensuring that when we arrived, everything would be set.",[16,3264,3265],{},"The booking was seamless, no friction at all. In fact, I could have sworn it was the smoothest reservation experience I'd ever had — like a moment of rare perfection in a world of chaos. But then, the moment of truth arrived.",[16,3267,3268],{},"I stepped in, walked up confidently to my designated table… and someone else was already sitting there.",[16,3270,3271],{},"I approached the host.",[16,3273,3274],{},[30,3275,3276],{},"\"Excuse me, I had a reservation for this spot.\"",[16,3278,3279],{},[30,3280,3281],{},"\"Ah, yes. Unfortunately, it's already occupied.\"",[16,3283,3284],{},[30,3285,3286],{},"\"I don't understand. I made a reservation. Do you have my reservation?\"",[16,3288,3289],{},[30,3290,3291],{},"\"Yes, we do, but the table is taken.\"",[16,3293,3294],{},[30,3295,3296],{},"\"But the reservation keeps the table here? That's why you have the reservation!\"",[16,3298,3299],{},[30,3300,3301],{},"\"I understand, sir, but — \"",[16,3303,3304],{},[30,3305,3306],{},"\"No, I don't think you do! You see, you know how to take a reservation, but you don't know how to hold the reservation. And really, the holding is the most important part of the reservation. Anybody can just take them!\"",[16,3308,3309],{},"The host blinked. I sighed. My girlfriend looked at me, amused but also wondering if she should start looking up alternatives. I, on the other hand, felt like I was in a sitcom episode, living out the very definition of modern frustration.",[16,3311,3312],{},"But this isn't just about restaurants.",[71,3314,3316],{"id":3315},"the-lost-spots-of-everyday-life","The Lost Spots of Everyday Life",[16,3318,3319],{},"Think about it. You've been here before, maybe not in a restaurant, but in some other equally annoying scenario.",[16,3321,3322,3323,2836],{},"Ever asked a friend to save you a seat in class, only to come back and find someone else sitting there, and your friend just shrugs like, ",[30,3324,3325],{},"\"I tried, bro.\"",[16,3327,3328,3329],{},"Or maybe you've been in a long queue, patiently waiting for your turn, and then — just for a moment — you step away. Maybe to grab something, maybe just to stretch. And when you return, the person behind you has edged forward, pretending like they've been next all along. You try to reason with them, but they just stare at you blankly like, ",[30,3330,3331],{},"\"I didn't see you there.\"",[16,3333,3334],{},"Or the worst — boarding a bus or train, where you find the perfect seat by the window. You drop your bag on it, step out for a second, and by the time you return, someone is already comfortably seated like they paid for the spot in blood.",[16,3336,3337,3338],{},"These little moments of frustration add up. Because in all of them, there's one underlying expectation: ",[66,3339,3340],{},"something should have held your place.",[16,3342,3343],{},"But it didn't.",[16,3345,3346],{},"And if you think that's bad, let's talk about when this happens online.",[71,3348,3350],{"id":3349},"the-digital-version-of-losing-your-spot","The Digital Version of Losing Your Spot",[16,3352,3353],{},"You're browsing through an online store, carefully filtering for the perfect item. You've selected the color, size, and quantity. Maybe you even checked the reviews. And then — oh, a notification pops up. You leave for just a second, come back, and refresh the page.",[16,3355,3356],{},[66,3357,3358],{},"Boom. Everything is gone.",[16,3360,3361,3362,3365],{},"Or maybe you're halfway through filling out a long, annoying form. You get distracted, switch tabs, and when you return — ",[66,3363,3364],{},"everything is wiped."," The form has reset like you were never there.",[16,3367,3368,3369,3372,3373],{},"Or worse, you find a great article, read halfway, and want to share it with a friend. You copy the link, send it over, but when they open it — ",[66,3370,3371],{},"it doesn't show what you were looking at."," They're at the homepage, lost and confused, asking, ",[30,3374,3375],{},"\"What exactly did you want me to see?\"",[16,3377,3378,3379,3382],{},"It's like telling a friend, ",[30,3380,3381],{},"\"Meet me at that cool café,\""," only for them to show up at a random gas station because, for some reason, your directions didn't hold.",[16,3384,3385],{},"And this is where websites mess up.",[16,3387,3388,3389,3392,3393,3396],{},"Just like my reservation should have ensured my seat remained mine, and just like your place in a queue should be honored, URL states should ",[66,3390,3391],{},"preserve user context."," Whether it's form inputs, filters, pagination, scroll positions, or shared links, your app should know how to ",[66,3394,3395],{},"hold"," a state, not just take it.",[16,3398,3399,3400],{},"Because let's be honest — ",[66,3401,3402],{},"anybody can take them.",[71,3404,3406],{"id":3405},"fixing-the-reservation-problem-url-as-a-state-manager","Fixing the Reservation Problem: URL as a State Manager",[16,3408,3409,3410,3413,3414,69],{},"Imagine if reservations worked like URLs. Instead of relying on a fragile, easily-overwritten system, the restaurant would store all reservation details in a ",[30,3411,3412],{},"permanent, accessible"," way. No mix-ups, no surprises. Your table would be marked, ",[30,3415,3416],{},"and that information would persist",[16,3418,3419],{},"This is exactly how URLs should work in web applications. A well-managed URL state ensures that user context is never lost — whether it's search filters, form inputs, pagination, or even scroll position. When a user refreshes, switches devices, or shares a link, everything should stay exactly as they left it.",[16,3421,3422],{},[66,3423,3424],{},"So how do we fix the problem?",[16,3426,3427,3428,3431],{},"Instead of treating URLs as just links, we should treat them as ",[66,3429,3430],{},"state managers"," — a single source of truth that keeps track of where users are and what they're doing.",[16,3433,1641,3434,1644],{},[30,3435,3436],{},"nuqs",[71,3438,3440],{"id":3439},"nuqs-making-url-state-management-effortless","Nuqs: Making URL State Management Effortless",[16,3442,3443,3444,3446,3447,3449],{},"One of my favorite tools to use is ",[66,3445,3436],{},". I first discovered ",[30,3448,3436],{}," last year while revamping a project, and it instantly clicked. It felt like using useState, but for URLs.",[16,3451,3452,3453,3456],{},"It was seamless — like a reservation system that actually works. No weird resets, no lost state, just smooth navigation. It integrates beautifully with both server and client environments, and with the rise of ",[66,3454,3455],{},"SSR",", it's a game-changer.",[16,3458,3459,3460,2836],{},"And if you're using ",[66,3461,3462],{},"Next.js",[16,3464,3465],{},"Well, let's just say you've got yourself the perfect date.",[16,3467,3468],{},"So, whether it's a dinner reservation, a classroom seat, or your place in a digital space, remember this:",[16,3470,3471],{},[66,3472,3473],{},"Taking a spot is easy. Holding it is what truly matters.",[71,3475,3477],{"id":3476},"setting-up-nuqs-keeping-your-spot-in-the-digital-world","Setting Up Nuqs: Keeping Your Spot in the Digital World",[16,3479,3480],{},"A reservation system that actually works — that's what I needed. Not just for dinner, but for my apps. No more lost filters, wiped-out forms, or reset states. If I left something exactly the way I wanted it, I expected it to stay that way.",[16,3482,3483],{},"That's where Nuqs came in. But before I could fully enjoy its magic, I had to set it up properly. Just like how you don't walk into a restaurant and expect a table to set itself, you need to prepare your app to hold state effortlessly.",[71,3485,3487],{"id":3486},"step-1-installing-nuqs","Step 1: Installing Nuqs",[16,3489,3490],{},"The first step was making sure Nuqs was in my project. Installing it was as easy as reserving a spot with a single click:",[145,3492,3494],{"className":147,"code":3493,"language":149,"meta":21,"style":21},"pnpm add nuqs\n# or\nnpm install nuqs\n# or\nyarn add nuqs\n",[151,3495,3496,3505,3510,3518,3522],{"__ignoreMap":21},[103,3497,3498,3500,3502],{"class":155,"line":156},[103,3499,1730],{"class":159},[103,3501,1733],{"class":163},[103,3503,3504],{"class":163}," nuqs\n",[103,3506,3507],{"class":155,"line":223},[103,3508,3509],{"class":449},"# or\n",[103,3511,3512,3514,3516],{"class":155,"line":233},[103,3513,160],{"class":159},[103,3515,164],{"class":163},[103,3517,3504],{"class":163},[103,3519,3520],{"class":155,"line":248},[103,3521,3509],{"class":449},[103,3523,3524,3527,3529],{"class":155,"line":259},[103,3525,3526],{"class":159},"yarn",[103,3528,1733],{"class":163},[103,3530,3504],{"class":163},[16,3532,3533],{},"With that done, I was one step closer to never losing my place again.",[71,3535,3537],{"id":3536},"step-2-configuring-nuqs-in-the-root-layout","Step 2: Configuring Nuqs in the Root Layout",[16,3539,3540],{},"Just like a restaurant needs a reservation system in place, my app needed Nuqs to be present across all pages. The best way to do that? Wrap the entire application in a provider that ensures state persistence across routes.",[16,3542,3543],{},"In my app.tsx, I set up Nuqs like this:",[145,3545,3547],{"className":919,"code":3546,"language":921,"meta":21,"style":21},"import { NuqsAdapter } from 'nuqs\u002Fadapters\u002Fnext\u002Fapp'\nimport { type ReactNode } from 'react'\n\nexport default function RootLayout({\n  children\n}: {\n  children: ReactNode\n}) {\n  return (\n    \u003Chtml>\n      \u003Cbody>\n        \u003CNuqsAdapter>{children}\u003C\u002FNuqsAdapter>\n      \u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  )\n}\n",[151,3548,3549,3561,3578,3582,3595,3600,3608,3617,3621,3627,3635,3643,3656,3664,3672,3677],{"__ignoreMap":21},[103,3550,3551,3553,3556,3558],{"class":155,"line":156},[103,3552,295],{"class":294},[103,3554,3555],{"class":219}," { NuqsAdapter } ",[103,3557,301],{"class":294},[103,3559,3560],{"class":163}," 'nuqs\u002Fadapters\u002Fnext\u002Fapp'\n",[103,3562,3563,3565,3567,3570,3573,3575],{"class":155,"line":223},[103,3564,295],{"class":294},[103,3566,1868],{"class":219},[103,3568,3569],{"class":294},"type",[103,3571,3572],{"class":219}," ReactNode } ",[103,3574,301],{"class":294},[103,3576,3577],{"class":163}," 'react'\n",[103,3579,3580],{"class":155,"line":233},[103,3581,327],{"emptyLinePlaceholder":326},[103,3583,3584,3586,3588,3590,3593],{"class":155,"line":248},[103,3585,367],{"class":294},[103,3587,370],{"class":294},[103,3589,980],{"class":294},[103,3591,3592],{"class":159}," RootLayout",[103,3594,444],{"class":219},[103,3596,3597],{"class":155,"line":259},[103,3598,3599],{"class":765},"  children\n",[103,3601,3602,3604,3606],{"class":155,"line":265},[103,3603,1002],{"class":219},[103,3605,338],{"class":294},[103,3607,656],{"class":219},[103,3609,3610,3612,3614],{"class":155,"line":475},[103,3611,990],{"class":765},[103,3613,338],{"class":294},[103,3615,3616],{"class":159}," ReactNode\n",[103,3618,3619],{"class":155,"line":480},[103,3620,1050],{"class":219},[103,3622,3623,3625],{"class":155,"line":486},[103,3624,1109],{"class":294},[103,3626,1112],{"class":219},[103,3628,3629,3631,3633],{"class":155,"line":495},[103,3630,1118],{"class":219},[103,3632,1122],{"class":1121},[103,3634,1142],{"class":219},[103,3636,3637,3639,3641],{"class":155,"line":851},[103,3638,1136],{"class":219},[103,3640,1139],{"class":1121},[103,3642,1142],{"class":219},[103,3644,3645,3647,3650,3652,3654],{"class":155,"line":857},[103,3646,1148],{"class":219},[103,3648,3649],{"class":226},"NuqsAdapter",[103,3651,1154],{"class":219},[103,3653,3649],{"class":226},[103,3655,1142],{"class":219},[103,3657,3658,3660,3662],{"class":155,"line":862},[103,3659,1164],{"class":219},[103,3661,1139],{"class":1121},[103,3663,1142],{"class":219},[103,3665,3666,3668,3670],{"class":155,"line":870},[103,3667,1174],{"class":219},[103,3669,1122],{"class":1121},[103,3671,1142],{"class":219},[103,3673,3674],{"class":155,"line":876},[103,3675,3676],{"class":219},"  )\n",[103,3678,3679],{"class":155,"line":901},[103,3680,268],{"class":219},[16,3682,3683],{},"This was like having the maître d' of my app, making sure everything stayed exactly where it was supposed to.",[16,3685,3686],{},"And just like that, my application was ready. But what good is a reservation system if you don't use it? It was time to put Nuqs into action.",[71,3688,3690],{"id":3689},"basic-usage-the-counter-that-remembers","Basic Usage: The Counter That Remembers",[16,3692,3693],{},"Now, let's talk about an everyday situation where Nuqs shines.",[16,3695,3696],{},"Imagine you're counting something important — maybe reps at the gym, the number of coffees you've had today, or how many times you've reloaded Twitter. Now imagine refreshing the page and losing count. Frustrating, right?",[16,3698,3699],{},"That's where Nuqs steps in.",[16,3701,3702],{},"Take a look at this simple counter demo.",[145,3704,3706],{"className":919,"code":3705,"language":921,"meta":21,"style":21},"\u002F\u002F client.tsx\n\n'use client';\n\nimport { Button } from '@\u002Fcomponents\u002Fui\u002Fbutton';\nimport { Minus, Plus } from 'lucide-react';\nimport { parseAsInteger, useQueryState } from 'nuqs';\n\nexport default function BasicCounterDemoPage() {\n  const [counter, setCounter] = useQueryState(\n    'counter',\n    parseAsInteger.withDefault(0)\n  );\n\n  return (\n    \u003Cdiv className='min-h-screen flex items-center justify-center bg-gradient-to-r from-blue-50 to-indigo-50'>\n      \u003Cdiv className='bg-white p-8 rounded-xl shadow-lg'>\n        \u003Ch1 className='text-3xl font-bold text-gray-800 mb-6 text-center'>\n          Interactive Counter\n        \u003C\u002Fh1>\n        \u003Cdiv className='flex flex-col items-center gap-6'>\n          \u003Cspan className='text-4xl font-bold text-indigo-600 tabular-nums'>\n            {counter}\n          \u003C\u002Fspan>\n          \u003Cdiv className='flex items-center gap-4'>\n            \u003CButton\n              onClick={() => setCounter((x) => Math.max(1, x - 1))}\n              className='bg-indigo-600 hover:bg-indigo-700 transition-colors'\n            >\n              \u003CMinus className='w-5 h-5' \u002F>\n            \u003C\u002FButton>\n            \u003CButton\n              onClick={() => setCounter((x) => x + 1)}\n              className='bg-indigo-600 hover:bg-indigo-700 transition-colors'\n            >\n              \u003CPlus className='w-5 h-5' \u002F>\n            \u003C\u002FButton>\n          \u003C\u002Fdiv>\n          \u003CButton\n            onClick={() => setCounter(null)}\n            variant='outline'\n            className='text-indigo-600 border-indigo-600 hover:bg-indigo-50'\n          >\n            Reset Counter\n          \u003C\u002FButton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n",[151,3707,3708,3713,3717,3724,3728,3741,3755,3769,3773,3786,3808,3815,3831,3835,3839,3845,3860,3875,3890,3895,3903,3918,3933,3938,3946,3961,3968,4016,4026,4031,4049,4058,4064,4095,4103,4107,4122,4130,4138,4144,4163,4172,4181,4185,4190,4198,4206,4214,4222,4226],{"__ignoreMap":21},[103,3709,3710],{"class":155,"line":156},[103,3711,3712],{"class":449},"\u002F\u002F client.tsx\n",[103,3714,3715],{"class":155,"line":223},[103,3716,327],{"emptyLinePlaceholder":326},[103,3718,3719,3722],{"class":155,"line":233},[103,3720,3721],{"class":163},"'use client'",[103,3723,307],{"class":219},[103,3725,3726],{"class":155,"line":248},[103,3727,327],{"emptyLinePlaceholder":326},[103,3729,3730,3732,3734,3736,3739],{"class":155,"line":259},[103,3731,295],{"class":294},[103,3733,2419],{"class":219},[103,3735,301],{"class":294},[103,3737,3738],{"class":163}," '@\u002Fcomponents\u002Fui\u002Fbutton'",[103,3740,307],{"class":219},[103,3742,3743,3745,3748,3750,3753],{"class":155,"line":265},[103,3744,295],{"class":294},[103,3746,3747],{"class":219}," { Minus, Plus } ",[103,3749,301],{"class":294},[103,3751,3752],{"class":163}," 'lucide-react'",[103,3754,307],{"class":219},[103,3756,3757,3759,3762,3764,3767],{"class":155,"line":475},[103,3758,295],{"class":294},[103,3760,3761],{"class":219}," { parseAsInteger, useQueryState } ",[103,3763,301],{"class":294},[103,3765,3766],{"class":163}," 'nuqs'",[103,3768,307],{"class":219},[103,3770,3771],{"class":155,"line":480},[103,3772,327],{"emptyLinePlaceholder":326},[103,3774,3775,3777,3779,3781,3784],{"class":155,"line":486},[103,3776,367],{"class":294},[103,3778,370],{"class":294},[103,3780,980],{"class":294},[103,3782,3783],{"class":159}," BasicCounterDemoPage",[103,3785,1251],{"class":219},[103,3787,3788,3790,3792,3795,3797,3800,3802,3804,3806],{"class":155,"line":495},[103,3789,1060],{"class":294},[103,3791,2626],{"class":219},[103,3793,3794],{"class":226},"counter",[103,3796,461],{"class":219},[103,3798,3799],{"class":226},"setCounter",[103,3801,2632],{"class":219},[103,3803,790],{"class":294},[103,3805,2637],{"class":159},[103,3807,2608],{"class":219},[103,3809,3810,3813],{"class":155,"line":851},[103,3811,3812],{"class":163},"    'counter'",[103,3814,245],{"class":219},[103,3816,3817,3820,3823,3825,3828],{"class":155,"line":857},[103,3818,3819],{"class":219},"    parseAsInteger.",[103,3821,3822],{"class":159},"withDefault",[103,3824,756],{"class":219},[103,3826,3827],{"class":226},"0",[103,3829,3830],{"class":219},")\n",[103,3832,3833],{"class":155,"line":862},[103,3834,1184],{"class":219},[103,3836,3837],{"class":155,"line":870},[103,3838,327],{"emptyLinePlaceholder":326},[103,3840,3841,3843],{"class":155,"line":876},[103,3842,1109],{"class":294},[103,3844,1112],{"class":219},[103,3846,3847,3849,3851,3853,3855,3858],{"class":155,"line":901},[103,3848,1118],{"class":219},[103,3850,1284],{"class":1121},[103,3852,2848],{"class":159},[103,3854,790],{"class":294},[103,3856,3857],{"class":163},"'min-h-screen flex items-center justify-center bg-gradient-to-r from-blue-50 to-indigo-50'",[103,3859,1142],{"class":219},[103,3861,3862,3864,3866,3868,3870,3873],{"class":155,"line":907},[103,3863,1136],{"class":219},[103,3865,1284],{"class":1121},[103,3867,2848],{"class":159},[103,3869,790],{"class":294},[103,3871,3872],{"class":163},"'bg-white p-8 rounded-xl shadow-lg'",[103,3874,1142],{"class":219},[103,3876,3877,3879,3881,3883,3885,3888],{"class":155,"line":1106},[103,3878,1148],{"class":219},[103,3880,1293],{"class":1121},[103,3882,2848],{"class":159},[103,3884,790],{"class":294},[103,3886,3887],{"class":163},"'text-3xl font-bold text-gray-800 mb-6 text-center'",[103,3889,1142],{"class":219},[103,3891,3892],{"class":155,"line":1115},[103,3893,3894],{"class":219},"          Interactive Counter\n",[103,3896,3897,3899,3901],{"class":155,"line":1133},[103,3898,2985],{"class":219},[103,3900,1293],{"class":1121},[103,3902,1142],{"class":219},[103,3904,3905,3907,3909,3911,3913,3916],{"class":155,"line":1145},[103,3906,1148],{"class":219},[103,3908,1284],{"class":1121},[103,3910,2848],{"class":159},[103,3912,790],{"class":294},[103,3914,3915],{"class":163},"'flex flex-col items-center gap-6'",[103,3917,1142],{"class":219},[103,3919,3920,3922,3924,3926,3928,3931],{"class":155,"line":1161},[103,3921,2872],{"class":219},[103,3923,103],{"class":1121},[103,3925,2848],{"class":159},[103,3927,790],{"class":294},[103,3929,3930],{"class":163},"'text-4xl font-bold text-indigo-600 tabular-nums'",[103,3932,1142],{"class":219},[103,3934,3935],{"class":155,"line":1171},[103,3936,3937],{"class":219},"            {counter}\n",[103,3939,3940,3942,3944],{"class":155,"line":1181},[103,3941,2974],{"class":219},[103,3943,103],{"class":1121},[103,3945,1142],{"class":219},[103,3947,3948,3950,3952,3954,3956,3959],{"class":155,"line":1187},[103,3949,2872],{"class":219},[103,3951,1284],{"class":1121},[103,3953,2848],{"class":159},[103,3955,790],{"class":294},[103,3957,3958],{"class":163},"'flex items-center gap-4'",[103,3960,1142],{"class":219},[103,3962,3963,3966],{"class":155,"line":2281},[103,3964,3965],{"class":219},"            \u003C",[103,3967,2875],{"class":226},[103,3969,3970,3973,3975,3978,3980,3983,3986,3989,3991,3993,3996,3999,4001,4004,4007,4010,4013],{"class":155,"line":2293},[103,3971,3972],{"class":159},"              onClick",[103,3974,790],{"class":294},[103,3976,3977],{"class":219},"{() ",[103,3979,772],{"class":294},[103,3981,3982],{"class":159}," setCounter",[103,3984,3985],{"class":219},"((",[103,3987,3988],{"class":765},"x",[103,3990,2687],{"class":219},[103,3992,772],{"class":294},[103,3994,3995],{"class":219}," Math.",[103,3997,3998],{"class":159},"max",[103,4000,756],{"class":219},[103,4002,4003],{"class":226},"1",[103,4005,4006],{"class":219},", x ",[103,4008,4009],{"class":294},"-",[103,4011,4012],{"class":226}," 1",[103,4014,4015],{"class":219},"))}\n",[103,4017,4018,4021,4023],{"class":155,"line":2314},[103,4019,4020],{"class":159},"              className",[103,4022,790],{"class":294},[103,4024,4025],{"class":163},"'bg-indigo-600 hover:bg-indigo-700 transition-colors'\n",[103,4027,4028],{"class":155,"line":2328},[103,4029,4030],{"class":219},"            >\n",[103,4032,4033,4036,4039,4041,4043,4046],{"class":155,"line":2334},[103,4034,4035],{"class":219},"              \u003C",[103,4037,4038],{"class":226},"Minus",[103,4040,2848],{"class":159},[103,4042,790],{"class":294},[103,4044,4045],{"class":163},"'w-5 h-5'",[103,4047,4048],{"class":219}," \u002F>\n",[103,4050,4051,4054,4056],{"class":155,"line":2339},[103,4052,4053],{"class":219},"            \u003C\u002F",[103,4055,2977],{"class":226},[103,4057,1142],{"class":219},[103,4059,4060,4062],{"class":155,"line":2356},[103,4061,3965],{"class":219},[103,4063,2875],{"class":226},[103,4065,4066,4068,4070,4072,4074,4076,4078,4080,4082,4084,4087,4090,4092],{"class":155,"line":2361},[103,4067,3972],{"class":159},[103,4069,790],{"class":294},[103,4071,3977],{"class":219},[103,4073,772],{"class":294},[103,4075,3982],{"class":159},[103,4077,3985],{"class":219},[103,4079,3988],{"class":765},[103,4081,2687],{"class":219},[103,4083,772],{"class":294},[103,4085,4086],{"class":219}," x ",[103,4088,4089],{"class":294},"+",[103,4091,4012],{"class":226},[103,4093,4094],{"class":219},")}\n",[103,4096,4097,4099,4101],{"class":155,"line":2795},[103,4098,4020],{"class":159},[103,4100,790],{"class":294},[103,4102,4025],{"class":163},[103,4104,4105],{"class":155,"line":2801},[103,4106,4030],{"class":219},[103,4108,4109,4111,4114,4116,4118,4120],{"class":155,"line":2806},[103,4110,4035],{"class":219},[103,4112,4113],{"class":226},"Plus",[103,4115,2848],{"class":159},[103,4117,790],{"class":294},[103,4119,4045],{"class":163},[103,4121,4048],{"class":219},[103,4123,4124,4126,4128],{"class":155,"line":2813},[103,4125,4053],{"class":219},[103,4127,2977],{"class":226},[103,4129,1142],{"class":219},[103,4131,4132,4134,4136],{"class":155,"line":2819},[103,4133,2974],{"class":219},[103,4135,1284],{"class":1121},[103,4137,1142],{"class":219},[103,4139,4140,4142],{"class":155,"line":2841},[103,4141,2872],{"class":219},[103,4143,2875],{"class":226},[103,4145,4146,4148,4150,4152,4154,4156,4158,4161],{"class":155,"line":2858},[103,4147,2892],{"class":159},[103,4149,790],{"class":294},[103,4151,3977],{"class":219},[103,4153,772],{"class":294},[103,4155,3982],{"class":159},[103,4157,756],{"class":219},[103,4159,4160],{"class":226},"null",[103,4162,4094],{"class":219},[103,4164,4165,4167,4169],{"class":155,"line":2869},[103,4166,2926],{"class":159},[103,4168,790],{"class":294},[103,4170,4171],{"class":163},"'outline'\n",[103,4173,4174,4176,4178],{"class":155,"line":2878},[103,4175,2881],{"class":159},[103,4177,790],{"class":294},[103,4179,4180],{"class":163},"'text-indigo-600 border-indigo-600 hover:bg-indigo-50'\n",[103,4182,4183],{"class":155,"line":2889},[103,4184,2937],{"class":219},[103,4186,4187],{"class":155,"line":2900},[103,4188,4189],{"class":219},"            Reset Counter\n",[103,4191,4192,4194,4196],{"class":155,"line":2923},[103,4193,2974],{"class":219},[103,4195,2977],{"class":226},[103,4197,1142],{"class":219},[103,4199,4200,4202,4204],{"class":155,"line":2934},[103,4201,2985],{"class":219},[103,4203,1284],{"class":1121},[103,4205,1142],{"class":219},[103,4207,4208,4210,4212],{"class":155,"line":2940},[103,4209,1164],{"class":219},[103,4211,1284],{"class":1121},[103,4213,1142],{"class":219},[103,4215,4216,4218,4220],{"class":155,"line":2946},[103,4217,1174],{"class":219},[103,4219,1284],{"class":1121},[103,4221,1142],{"class":219},[103,4223,4224],{"class":155,"line":2960},[103,4225,1184],{"class":219},[103,4227,4228],{"class":155,"line":2971},[103,4229,268],{"class":219},[71,4231,4233],{"id":4232},"how-it-works","How It Works",[96,4235,4236,4239,4242,4245],{},[99,4237,4238],{},"The counter state is stored in the URL as ?counter=number.",[99,4240,4241],{},"Clicking Plus (+) or Minus (-) updates the value while keeping it in sync.",[99,4243,4244],{},"Clicking Reset removes the state from the URL.",[99,4246,4247],{},"Even if the user refreshes the page or shares the link, the counter value remains intact.",[16,4249,4250,4253],{},[19,4251],{"alt":21,"src":4252},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F1024\u002F1*-7t31FDkCiVe9_fFN723tQ.gif",[30,4254,4255],{},"Nuqs Counter Demo",[16,4257,4258],{},"It's like saving your seat and coming back to find it exactly where you left it. No mix-ups. No \"Sorry, we gave it away.\" Just seamless, reliable state persistence.",[16,4260,4261],{},"With Nuqs, my app wasn't just taking reservations — it was holding them. And that made all the difference.",[71,4263,4265],{"id":4264},"building-a-comprehensive-table","Building a Comprehensive Table",[16,4267,4268],{},"Reserving a table is great, but what if you need a whole VIP section? In a dynamic app, handling more complex state persistence becomes crucial. That's where an advanced table setup comes in.",[71,4270,4272],{"id":4271},"advanced-tables-where-nuqs-shines","Advanced Tables: Where Nuqs Shines",[16,4274,4275],{},"A table is a great next step because it introduces:",[96,4277,4278,4284,4290,4296],{},[99,4279,4280,4283],{},[66,4281,4282],{},"Sorting"," — Allow users to order data dynamically",[99,4285,4286,4289],{},[66,4287,4288],{},"Filtering"," — Let users refine what they see",[99,4291,4292,4295],{},[66,4293,4294],{},"Pagination"," — Efficiently manage large datasets",[99,4297,4298,4301],{},[66,4299,4300],{},"State Persistence"," — Keep everything in sync via the URL",[71,4303,4305],{"id":4304},"setting-up-the-server-action","Setting Up the Server Action",[16,4307,4308,4309,4312],{},"First, let's create a ",[66,4310,4311],{},"server action"," to fetch data based on query parameters:",[145,4314,4316],{"className":285,"code":4315,"language":287,"meta":21,"style":21},"'use server'\n\nimport { getDatabaseResults } from '@\u002Fsrc\u002Flib\u002Fdb'\n\nexport async function fetchTableData({ page, sort, filter }: {\n  page?: number;\n  sort?: string;\n  filter?: string;\n}) {\n  return await getDatabaseResults({ page, sort, filter });\n}\n",[151,4317,4318,4323,4327,4339,4343,4376,4388,4399,4410,4414,4426],{"__ignoreMap":21},[103,4319,4320],{"class":155,"line":156},[103,4321,4322],{"class":163},"'use server'\n",[103,4324,4325],{"class":155,"line":223},[103,4326,327],{"emptyLinePlaceholder":326},[103,4328,4329,4331,4334,4336],{"class":155,"line":233},[103,4330,295],{"class":294},[103,4332,4333],{"class":219}," { getDatabaseResults } ",[103,4335,301],{"class":294},[103,4337,4338],{"class":163}," '@\u002Fsrc\u002Flib\u002Fdb'\n",[103,4340,4341],{"class":155,"line":248},[103,4342,327],{"emptyLinePlaceholder":326},[103,4344,4345,4347,4349,4351,4354,4357,4360,4362,4365,4367,4370,4372,4374],{"class":155,"line":259},[103,4346,367],{"class":294},[103,4348,977],{"class":294},[103,4350,980],{"class":294},[103,4352,4353],{"class":159}," fetchTableData",[103,4355,4356],{"class":219},"({ ",[103,4358,4359],{"class":765},"page",[103,4361,461],{"class":219},[103,4363,4364],{"class":765},"sort",[103,4366,461],{"class":219},[103,4368,4369],{"class":765},"filter",[103,4371,2563],{"class":219},[103,4373,338],{"class":294},[103,4375,656],{"class":219},[103,4377,4378,4381,4383,4386],{"class":155,"line":265},[103,4379,4380],{"class":765},"  page",[103,4382,1874],{"class":294},[103,4384,4385],{"class":226}," number",[103,4387,307],{"class":219},[103,4389,4390,4393,4395,4397],{"class":155,"line":475},[103,4391,4392],{"class":765},"  sort",[103,4394,1874],{"class":294},[103,4396,1042],{"class":226},[103,4398,307],{"class":219},[103,4400,4401,4404,4406,4408],{"class":155,"line":480},[103,4402,4403],{"class":765},"  filter",[103,4405,1874],{"class":294},[103,4407,1042],{"class":226},[103,4409,307],{"class":219},[103,4411,4412],{"class":155,"line":486},[103,4413,1050],{"class":219},[103,4415,4416,4418,4420,4423],{"class":155,"line":495},[103,4417,1109],{"class":294},[103,4419,793],{"class":294},[103,4421,4422],{"class":159}," getDatabaseResults",[103,4424,4425],{"class":219},"({ page, sort, filter });\n",[103,4427,4428],{"class":155,"line":851},[103,4429,268],{"class":219},[71,4431,4433],{"id":4432},"client-table-component","Client Table Component",[16,4435,4436],{},"Now, let's create a client-side table that syncs with the URL using Nuqs:",[145,4438,4440],{"className":919,"code":4439,"language":921,"meta":21,"style":21},"'use client'\n\nimport { useQueryState, parseAsString, parseAsInteger } from 'nuqs'\nimport { fetchTableData } from '@\u002Fsrc\u002Factions\u002FtableActions'\n\nexport default function AdvancedTable() {\n  const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1))\n  const [sort, setSort] = useQueryState('sort', parseAsString)\n  const [filter, setFilter] = useQueryState('filter', parseAsString)\n\n  const { data, error } = use(fetchTableData({ page, sort, filter }))\n\n  return (\n    \u003Cdiv>\n      \u003Cinput\n        type=\"text\"\n        placeholder=\"Filter...\"\n        value={filter ?? ''}\n        onChange={(e) => setFilter(e.target.value || null)}\n      \u002F>\n      \u003Cbutton onClick={() => setSort(sort === 'asc' ? 'desc' : 'asc')}>\n        Sort: {sort === 'asc' ? 'Descending' : 'Ascending'}\n      \u003C\u002Fbutton>\n      \u003Ctable>\n        \u003Cthead>\n          \u003Ctr>\n            \u003Cth>Name\u003C\u002Fth>\n            \u003Cth>Value\u003C\u002Fth>\n          \u003C\u002Ftr>\n        \u003C\u002Fthead>\n        \u003Ctbody>\n          {data?.map((item) => (\n            \u003Ctr key={item.id}>\n              \u003Ctd>{item.name}\u003C\u002Ftd>\n              \u003Ctd>{item.value}\u003C\u002Ftd>\n            \u003C\u002Ftr>\n          ))}\n        \u003C\u002Ftbody>\n      \u003C\u002Ftable>\n      \u003Cbutton onClick={() => setPage(page - 1)} disabled={page \u003C= 1}>Previous\u003C\u002Fbutton>\n      \u003Cbutton onClick={() => setPage(page + 1)}>Next\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  )\n}\n",[151,4441,4442,4447,4451,4463,4475,4479,4492,4528,4555,4581,4585,4612,4616,4622,4630,4637,4647,4657,4675,4704,4709,4750,4771,4779,4788,4797,4806,4820,4833,4841,4849,4858,4877,4891,4905,4918,4926,4931,4939,4947,4994,5023,5031,5035],{"__ignoreMap":21},[103,4443,4444],{"class":155,"line":156},[103,4445,4446],{"class":163},"'use client'\n",[103,4448,4449],{"class":155,"line":223},[103,4450,327],{"emptyLinePlaceholder":326},[103,4452,4453,4455,4458,4460],{"class":155,"line":233},[103,4454,295],{"class":294},[103,4456,4457],{"class":219}," { useQueryState, parseAsString, parseAsInteger } ",[103,4459,301],{"class":294},[103,4461,4462],{"class":163}," 'nuqs'\n",[103,4464,4465,4467,4470,4472],{"class":155,"line":248},[103,4466,295],{"class":294},[103,4468,4469],{"class":219}," { fetchTableData } ",[103,4471,301],{"class":294},[103,4473,4474],{"class":163}," '@\u002Fsrc\u002Factions\u002FtableActions'\n",[103,4476,4477],{"class":155,"line":259},[103,4478,327],{"emptyLinePlaceholder":326},[103,4480,4481,4483,4485,4487,4490],{"class":155,"line":265},[103,4482,367],{"class":294},[103,4484,370],{"class":294},[103,4486,980],{"class":294},[103,4488,4489],{"class":159}," AdvancedTable",[103,4491,1251],{"class":219},[103,4493,4494,4496,4498,4500,4502,4505,4507,4509,4511,4513,4516,4519,4521,4523,4525],{"class":155,"line":475},[103,4495,1060],{"class":294},[103,4497,2626],{"class":219},[103,4499,4359],{"class":226},[103,4501,461],{"class":219},[103,4503,4504],{"class":226},"setPage",[103,4506,2632],{"class":219},[103,4508,790],{"class":294},[103,4510,2637],{"class":159},[103,4512,756],{"class":219},[103,4514,4515],{"class":163},"'page'",[103,4517,4518],{"class":219},", parseAsInteger.",[103,4520,3822],{"class":159},[103,4522,756],{"class":219},[103,4524,4003],{"class":226},[103,4526,4527],{"class":219},"))\n",[103,4529,4530,4532,4534,4536,4538,4541,4543,4545,4547,4549,4552],{"class":155,"line":480},[103,4531,1060],{"class":294},[103,4533,2626],{"class":219},[103,4535,4364],{"class":226},[103,4537,461],{"class":219},[103,4539,4540],{"class":226},"setSort",[103,4542,2632],{"class":219},[103,4544,790],{"class":294},[103,4546,2637],{"class":159},[103,4548,756],{"class":219},[103,4550,4551],{"class":163},"'sort'",[103,4553,4554],{"class":219},", parseAsString)\n",[103,4556,4557,4559,4561,4563,4565,4568,4570,4572,4574,4576,4579],{"class":155,"line":486},[103,4558,1060],{"class":294},[103,4560,2626],{"class":219},[103,4562,4369],{"class":226},[103,4564,461],{"class":219},[103,4566,4567],{"class":226},"setFilter",[103,4569,2632],{"class":219},[103,4571,790],{"class":294},[103,4573,2637],{"class":159},[103,4575,756],{"class":219},[103,4577,4578],{"class":163},"'filter'",[103,4580,4554],{"class":219},[103,4582,4583],{"class":155,"line":495},[103,4584,327],{"emptyLinePlaceholder":326},[103,4586,4587,4589,4591,4593,4595,4597,4599,4601,4604,4606,4609],{"class":155,"line":851},[103,4588,1060],{"class":294},[103,4590,1868],{"class":219},[103,4592,2684],{"class":226},[103,4594,461],{"class":219},[103,4596,1898],{"class":226},[103,4598,2208],{"class":219},[103,4600,790],{"class":294},[103,4602,4603],{"class":159}," use",[103,4605,756],{"class":219},[103,4607,4608],{"class":159},"fetchTableData",[103,4610,4611],{"class":219},"({ page, sort, filter }))\n",[103,4613,4614],{"class":155,"line":857},[103,4615,327],{"emptyLinePlaceholder":326},[103,4617,4618,4620],{"class":155,"line":862},[103,4619,1109],{"class":294},[103,4621,1112],{"class":219},[103,4623,4624,4626,4628],{"class":155,"line":870},[103,4625,1118],{"class":219},[103,4627,1284],{"class":1121},[103,4629,1142],{"class":219},[103,4631,4632,4634],{"class":155,"line":876},[103,4633,1136],{"class":219},[103,4635,4636],{"class":1121},"input\n",[103,4638,4639,4642,4644],{"class":155,"line":901},[103,4640,4641],{"class":159},"        type",[103,4643,790],{"class":294},[103,4645,4646],{"class":163},"\"text\"\n",[103,4648,4649,4652,4654],{"class":155,"line":907},[103,4650,4651],{"class":159},"        placeholder",[103,4653,790],{"class":294},[103,4655,4656],{"class":163},"\"Filter...\"\n",[103,4658,4659,4662,4664,4667,4670,4673],{"class":155,"line":1106},[103,4660,4661],{"class":159},"        value",[103,4663,790],{"class":294},[103,4665,4666],{"class":219},"{filter ",[103,4668,4669],{"class":294},"??",[103,4671,4672],{"class":163}," ''",[103,4674,268],{"class":219},[103,4676,4677,4680,4682,4685,4687,4689,4691,4694,4697,4699,4702],{"class":155,"line":1115},[103,4678,4679],{"class":159},"        onChange",[103,4681,790],{"class":294},[103,4683,4684],{"class":219},"{(",[103,4686,1857],{"class":765},[103,4688,2687],{"class":219},[103,4690,772],{"class":294},[103,4692,4693],{"class":159}," setFilter",[103,4695,4696],{"class":219},"(e.target.value ",[103,4698,817],{"class":294},[103,4700,4701],{"class":226}," null",[103,4703,4094],{"class":219},[103,4705,4706],{"class":155,"line":1133},[103,4707,4708],{"class":219},"      \u002F>\n",[103,4710,4711,4713,4716,4719,4721,4723,4725,4728,4731,4733,4736,4739,4742,4745,4747],{"class":155,"line":1145},[103,4712,1136],{"class":219},[103,4714,4715],{"class":1121},"button",[103,4717,4718],{"class":159}," onClick",[103,4720,790],{"class":294},[103,4722,3977],{"class":219},[103,4724,772],{"class":294},[103,4726,4727],{"class":159}," setSort",[103,4729,4730],{"class":219},"(sort ",[103,4732,2825],{"class":294},[103,4734,4735],{"class":163}," 'asc'",[103,4737,4738],{"class":294}," ?",[103,4740,4741],{"class":163}," 'desc'",[103,4743,4744],{"class":294}," :",[103,4746,4735],{"class":163},[103,4748,4749],{"class":219},")}>\n",[103,4751,4752,4755,4757,4759,4761,4764,4766,4769],{"class":155,"line":1161},[103,4753,4754],{"class":219},"        Sort: {sort ",[103,4756,2825],{"class":294},[103,4758,4735],{"class":163},[103,4760,4738],{"class":294},[103,4762,4763],{"class":163}," 'Descending'",[103,4765,4744],{"class":294},[103,4767,4768],{"class":163}," 'Ascending'",[103,4770,268],{"class":219},[103,4772,4773,4775,4777],{"class":155,"line":1171},[103,4774,1164],{"class":219},[103,4776,4715],{"class":1121},[103,4778,1142],{"class":219},[103,4780,4781,4783,4786],{"class":155,"line":1181},[103,4782,1136],{"class":219},[103,4784,4785],{"class":1121},"table",[103,4787,1142],{"class":219},[103,4789,4790,4792,4795],{"class":155,"line":1187},[103,4791,1148],{"class":219},[103,4793,4794],{"class":1121},"thead",[103,4796,1142],{"class":219},[103,4798,4799,4801,4804],{"class":155,"line":2281},[103,4800,2872],{"class":219},[103,4802,4803],{"class":1121},"tr",[103,4805,1142],{"class":219},[103,4807,4808,4810,4813,4816,4818],{"class":155,"line":2293},[103,4809,3965],{"class":219},[103,4811,4812],{"class":1121},"th",[103,4814,4815],{"class":219},">Name\u003C\u002F",[103,4817,4812],{"class":1121},[103,4819,1142],{"class":219},[103,4821,4822,4824,4826,4829,4831],{"class":155,"line":2314},[103,4823,3965],{"class":219},[103,4825,4812],{"class":1121},[103,4827,4828],{"class":219},">Value\u003C\u002F",[103,4830,4812],{"class":1121},[103,4832,1142],{"class":219},[103,4834,4835,4837,4839],{"class":155,"line":2328},[103,4836,2974],{"class":219},[103,4838,4803],{"class":1121},[103,4840,1142],{"class":219},[103,4842,4843,4845,4847],{"class":155,"line":2334},[103,4844,2985],{"class":219},[103,4846,4794],{"class":1121},[103,4848,1142],{"class":219},[103,4850,4851,4853,4856],{"class":155,"line":2339},[103,4852,1148],{"class":219},[103,4854,4855],{"class":1121},"tbody",[103,4857,1142],{"class":219},[103,4859,4860,4863,4866,4868,4871,4873,4875],{"class":155,"line":2356},[103,4861,4862],{"class":219},"          {data?.",[103,4864,4865],{"class":159},"map",[103,4867,3985],{"class":219},[103,4869,4870],{"class":765},"item",[103,4872,2687],{"class":219},[103,4874,772],{"class":294},[103,4876,1112],{"class":219},[103,4878,4879,4881,4883,4886,4888],{"class":155,"line":2361},[103,4880,3965],{"class":219},[103,4882,4803],{"class":1121},[103,4884,4885],{"class":159}," key",[103,4887,790],{"class":294},[103,4889,4890],{"class":219},"{item.id}>\n",[103,4892,4893,4895,4898,4901,4903],{"class":155,"line":2795},[103,4894,4035],{"class":219},[103,4896,4897],{"class":1121},"td",[103,4899,4900],{"class":219},">{item.name}\u003C\u002F",[103,4902,4897],{"class":1121},[103,4904,1142],{"class":219},[103,4906,4907,4909,4911,4914,4916],{"class":155,"line":2801},[103,4908,4035],{"class":219},[103,4910,4897],{"class":1121},[103,4912,4913],{"class":219},">{item.value}\u003C\u002F",[103,4915,4897],{"class":1121},[103,4917,1142],{"class":219},[103,4919,4920,4922,4924],{"class":155,"line":2806},[103,4921,4053],{"class":219},[103,4923,4803],{"class":1121},[103,4925,1142],{"class":219},[103,4927,4928],{"class":155,"line":2813},[103,4929,4930],{"class":219},"          ))}\n",[103,4932,4933,4935,4937],{"class":155,"line":2819},[103,4934,2985],{"class":219},[103,4936,4855],{"class":1121},[103,4938,1142],{"class":219},[103,4940,4941,4943,4945],{"class":155,"line":2841},[103,4942,1164],{"class":219},[103,4944,4785],{"class":1121},[103,4946,1142],{"class":219},[103,4948,4949,4951,4953,4955,4957,4959,4961,4964,4967,4969,4971,4974,4977,4979,4982,4985,4987,4990,4992],{"class":155,"line":2858},[103,4950,1136],{"class":219},[103,4952,4715],{"class":1121},[103,4954,4718],{"class":159},[103,4956,790],{"class":294},[103,4958,3977],{"class":219},[103,4960,772],{"class":294},[103,4962,4963],{"class":159}," setPage",[103,4965,4966],{"class":219},"(page ",[103,4968,4009],{"class":294},[103,4970,4012],{"class":226},[103,4972,4973],{"class":219},")} ",[103,4975,4976],{"class":159},"disabled",[103,4978,790],{"class":294},[103,4980,4981],{"class":219},"{page ",[103,4983,4984],{"class":294},"\u003C=",[103,4986,4012],{"class":226},[103,4988,4989],{"class":219},"}>Previous\u003C\u002F",[103,4991,4715],{"class":1121},[103,4993,1142],{"class":219},[103,4995,4996,4998,5000,5002,5004,5006,5008,5010,5012,5014,5016,5019,5021],{"class":155,"line":2869},[103,4997,1136],{"class":219},[103,4999,4715],{"class":1121},[103,5001,4718],{"class":159},[103,5003,790],{"class":294},[103,5005,3977],{"class":219},[103,5007,772],{"class":294},[103,5009,4963],{"class":159},[103,5011,4966],{"class":219},[103,5013,4089],{"class":294},[103,5015,4012],{"class":226},[103,5017,5018],{"class":219},")}>Next\u003C\u002F",[103,5020,4715],{"class":1121},[103,5022,1142],{"class":219},[103,5024,5025,5027,5029],{"class":155,"line":2878},[103,5026,1174],{"class":219},[103,5028,1284],{"class":1121},[103,5030,1142],{"class":219},[103,5032,5033],{"class":155,"line":2889},[103,5034,3676],{"class":219},[103,5036,5037],{"class":155,"line":2900},[103,5038,268],{"class":219},[16,5040,5041],{},"This ensures:",[96,5043,5044,5050,5056],{},[99,5045,5046,5047],{},"URL-based ",[66,5048,5049],{},"pagination, sorting, and filtering",[99,5051,5052,5055],{},[66,5053,5054],{},"State persistence"," across refreshes and navigation",[99,5057,5058,5061],{},[66,5059,5060],{},"Seamless user experience"," with Nuqs managing query states",[71,5063,5065],{"id":5064},"final-thoughts-holding-the-spot-that-matters","Final Thoughts: Holding the Spot That Matters",[16,5067,5068,5069,69],{},"At the end of the day, whether it's a table at a restaurant, a seat in a lecture hall, or your place in a digital experience, what we really want is simple: ",[66,5070,5071],{},"to not lose our spot",[16,5073,5074,5075,69],{},"Just like a well-managed reservation system ensures your table stays yours, a well-structured URL state ensures that users never feel lost or reset. It's not just about good UX — it's about ",[66,5076,5077],{},"respecting user intent",[16,5079,5080,5081,5084,5085,5088,5089,5092,5093,5096],{},"That's where ",[66,5082,5083],{},"Nuqs"," stands out. Unlike useSearchParams, which is limited to basic query strings, or ",[66,5086,5087],{},"state managers like Zustand and Redux",", which primarily handle ",[66,5090,5091],{},"in-app state"," (and lose it on refresh unless you introduce a persistence layer like localStorage), Nuqs ensures that state persists ",[66,5094,5095],{},"naturally via the URL","—without extra setup.",[16,5098,5099,5100,5103,5104,5107,5108,5111],{},"Beyond just improving user experience, ",[66,5101,5102],{},"persisting state in URLs has real advantages"," — it makes content more ",[66,5105,5106],{},"SEO-friendly",", allowing users to share stateful URLs effortlessly. It also enhances ",[66,5109,5110],{},"accessibility",", ensuring users returning via bookmarks or assistive technologies don't start from scratch.",[71,5113,5115],{"id":5114},"a-quick-note-on-limits","🚦 A Quick Note on Limits",[16,5117,5118,5119,5122],{},"Of course, even the best reservation systems have their limits — there's only so much space in a restaurant, and only so many seats in a theater. URLs are the same. While Nuqs lets you hold your spot seamlessly, ",[66,5120,5121],{},"every browser has a max URL length"," — and just like a restaurant that can't fit an entire wedding party at one table, a URL isn't the place for storing massive application state.",[16,5124,5125,5126,5129,5130,5133],{},"And just like some venues might have a \"no back-to-back reservations\" policy, browsers also ",[66,5127,5128],{},"throttle rapid URL updates"," to ensure smooth performance. Luckily, Nuqs ",[66,5131,5132],{},"handles this for you",", so you don't have to worry about overloading the system.",[16,5135,5136,5137,5140,5141],{},"So, as always, ",[66,5138,5139],{},"balance is key",". Not every piece of state belongs in the URL — ",[66,5142,5143],{},"but when it does, Nuqs makes sure it stays there.",[16,5145,5146,5147],{},"Because at the end of the day, the best experiences are the ones that let you leave — and come back — ",[66,5148,5149],{},"without losing your place.",[1479,5151,5152],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":21,"searchDepth":223,"depth":223,"links":5154},[5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170],{"id":3253,"depth":233,"text":3254},{"id":3315,"depth":223,"text":3316},{"id":3349,"depth":223,"text":3350},{"id":3405,"depth":223,"text":3406},{"id":3439,"depth":223,"text":3440},{"id":3476,"depth":223,"text":3477},{"id":3486,"depth":223,"text":3487},{"id":3536,"depth":223,"text":3537},{"id":3689,"depth":223,"text":3690},{"id":4232,"depth":223,"text":4233},{"id":4264,"depth":223,"text":4265},{"id":4271,"depth":223,"text":4272},{"id":4304,"depth":223,"text":4305},{"id":4432,"depth":223,"text":4433},{"id":5064,"depth":223,"text":5065},{"id":5114,"depth":223,"text":5115},"https:\u002F\u002Fiamlope.medium.com\u002Fnuqs-because-urls-should-do-more-5d5d86e873c1","2025-02-17","Type-safe URL search-param state management in Next.js with nuqs, so user context persists across refreshes and shared links.",{},"\u002Fblog\u002Fnuqs-because-urls-should-do-more","7min",{"title":3248,"description":5173},"blog\u002Fnuqs-because-urls-should-do-more","iKRTsLoF7x_HErz_S3oeglrXQhwgHJ4Vtd1IQkM2_mA",1781421037022]