Help
RSS
API
Feed
Maltego
Contact
Domain > ratu.dev
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2026-02-20
104.26.10.183
(
ClassC
)
Port 443
HTTP/1.1 200 OKDate: Fri, 20 Feb 2026 05:55:48 GMTContent-Type: text/html; charsetutf-8Transfer-Encoding: chunkedConnection: keep-aliveCache-Control: s-maxage31536000ETag: ypictb91ju1bcrVary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, accept-encodingx-nextjs-cache: HITx-nextjs-prerender: 1,1x-nextjs-stale-time: 300Report-To: {group:cf-nel,max_age:604800,endpoints:{url:https://a.nel.cloudflare.com/report/v4?sVgaYUFW664nDPYyQyMJ%2BfnNwDuFtSOGU3iJnSvzcQJDLjRDVwGiXqjxov6JP01bffZcCYlFvqrBsSYfoPtIR9YDdNuXs91I%3D}}Nel: {report_to:cf-nel,success_fraction:0.0,max_age:604800}Server: cloudflareCF-RAY: 9d0bc1d3996296ba-PDXalt-svc: h3:443; ma86400 !DOCTYPE html>!--ZvXlnZCeXv2FqHXdbzTf2-->html langen classlight>head>meta charSetutf-8/>meta charSetutf-8/>meta nameviewport contentwidthdevice-width, initial-scale1 maximum-scale1/>meta nameviewport contentwidthdevice-width, initial-scale1/>link relpreload href/_next/static/media/031a93a156d22825-s.p.woff2 asfont crossorigin typefont/woff2/>link relpreload href/_next/static/media/9cf9c6e84ed13b5e-s.p.woff2 asfont crossorigin typefont/woff2/>link relpreload asimage imageSrcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 920w imageSizes520px/>link relstylesheet href/_next/static/css/56aca9a88ce3f35c.css data-precedencenext/>link relstylesheet href/_next/static/css/2cceed9f73df3333.css data-precedencenext/>link relpreload asscript fetchPrioritylow href/_next/static/chunks/webpack-84ab9ee953850d3a.js/>script src/_next/static/chunks/c54bd661-be6deb9a8ae76eca.js async>/script>script src/_next/static/chunks/823-a27d51e62cda3fd1.js async>/script>script src/_next/static/chunks/main-app-9352b35e094074e4.js async>/script>script src/_next/static/chunks/440-a720412ecf546db4.js async>/script>script src/_next/static/chunks/144-22d3e9edf8340076.js async>/script>script src/_next/static/chunks/944-a7fcd457c1336867.js async>/script>script src/_next/static/chunks/524-c4a13ce6e586703d.js async>/script>script src/_next/static/chunks/app/layout-2b304fe192248531.js async>/script>script src/_next/static/chunks/713-a98e84a52def2dba.js async>/script>script src/_next/static/chunks/908-64a17f68de53ce6d.js async>/script>script src/_next/static/chunks/183-206a2249f9a2c3ad.js async>/script>script src/_next/static/chunks/588-d881c5c2c5e86f7b.js async>/script>script src/_next/static/chunks/app/page-d7607bcac0e5d501.js async>/script>script src/_next/static/chunks/app/error-38231a477418fed8.js async>/script>link relpreload hrefhttps://cloud.umami.is/script.js asscript/>link relexpect href#_R_ blockingrender/>link relsitemap href/sitemap.xml/>link relicon href/favicon.ico/>link relapple-touch-icon href/apple-touch-icon.png/>link relpreconnect hrefhttps://api-gateway.umami.dev/>meta namenext-size-adjust content/>title>Home | Raman Ramanouski | ratu.dev/title>meta namedescription contentPersonal blog | Raman Ramanouski - portfolio overview, including links to blog posts, projects, snippets/>meta nameauthor contentRaman Ramanouski/>meta namecreator contentRaman Ramanouski/>meta propertyog:title contentHome | Raman Ramanouski | ratu.dev/>meta propertyog:description contentPersonal blog | Raman Ramanouski - portfolio overview, including links to blog posts, projects, snippets/>meta propertyog:image contenthttps://ratu.dev/images/opengraph-image.png/>meta nametwitter:card contentsummary_large_image/>meta nametwitter:title contentHome | Raman Ramanouski | ratu.dev/>meta nametwitter:description contentPersonal blog | Raman Ramanouski - portfolio overview, including links to blog posts, projects, snippets/>meta nametwitter:image contenthttps://ratu.dev/images/opengraph-image.png/>script src/_next/static/chunks/polyfills-42372ed130431b0a.js noModule>/script>/head>body class__variable_e95cc6 __variable_622c96>div hidden>!--$-->!--/$-->/div>main>div classabsolute inset-0 h-full w-full overflow-hidden animate-fadeIn3>img altBackground image loadinglazy width1024 height1024 decodingasync data-nimg1 classabsolute inset-0 h-full w-full scale-1.02 object-cover opacity-50 blur-2xl dark:opacity-30 stylecolor:transparent srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality80/_next/static/media/sample.4d99662a.png 1x srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality80/_next/static/media/sample.4d99662a.png/>div classabsolute inset-0 h-full w-full bg-gradient-to-b from-transparent to-#f3f4f6 dark:to-black>/div>/div>div idmobile-nav-portal-target>/div>div classflex flex-col justify-center relative w-full max-w-65rem mx-auto mb--1px z-20>div classw-full flex md:px-8 px-6 border-blue-100 md:h-20 h-16 relative>div classflex justify-between items-center text-white text-base min-h-59px w-full flex-wrap top-6px z-10 max-w-1200px mx-auto>div>a href/>div classtext-white md:p-1 flex items-center md:inline-block cursor-pointer>svg width39 height40 viewBox0 0 39 40 fillnone xmlnshttp://www.w3.org/2000/svg>g clip-pathurl(#clip0_121_23)>path dM0 4C0 1.79086 1.79086 0 4 0H35C37.2091 0 39 1.79086 39 4V36C39 38.2091 37.2091 40 35 40H4C1.79086 40 0 38.2091 0 36V4Z fill#010100>/path>path dM13.472 12.68H11.61V18H9.12101V4.89001H14.099C15.3783 4.89001 16.398 5.24468 17.158 5.95401C17.918 6.65068 18.298 7.60068 18.298 8.80401C18.298 9.66534 18.0953 10.3937 17.69 10.989C17.2973 11.5843 16.7273 12.0213 15.98 12.3L18.83 18H15.961L13.472 12.68ZM11.61 10.609H13.966C14.5487 10.609 14.9983 10.457 15.315 10.153C15.6443 9.83634 15.809 9.38668 15.809 8.80401C15.809 8.27201 15.6443 7.84768 15.315 7.53101C14.9857 7.21434 14.536 7.05602 13.966 7.05602H11.61V10.609ZM17.31 24.056H13.966V35H11.458V24.056H8.11401V21.89H17.31V24.056ZM24.9498 35.114C24.0631 35.114 23.2588 34.9303 22.5368 34.563C21.8274 34.183 21.2701 33.6573 20.8648 32.986C20.4594 32.302 20.2568 31.5293 20.2568 30.668V21.89H22.7458V30.592C22.7458 31.3393 22.9421 31.922 23.3348 32.34C23.7274 32.7453 24.2658 32.948 24.9498 32.948C25.6338 32.948 26.1721 32.7453 26.5648 32.34C26.9701 31.922 27.1728 31.3393 27.1728 30.592V21.89H29.6808V30.668C29.6808 31.5293 29.4718 32.302 29.0538 32.986C28.6484 33.6573 28.0848 34.183 27.3628 34.563C26.6534 34.9303 25.8491 35.114 24.9498 35.114Z fillwhite>/path>path dM25.186 4.88599C26.0727 4.88599 26.877 5.06966 27.599 5.43699C28.3083 5.81699 28.8657 6.34266 29.271 7.01399C29.6763 7.69799 29.879 8.47066 29.879 9.33199V18.11H27.39V9.40799C27.39 8.66066 27.1937 8.07799 26.801 7.65999C26.4083 7.25466 25.87 7.05199 25.186 7.05199C24.502 7.05199 23.9637 7.25466 23.571 7.65999C23.1657 8.07799 22.963 8.66066 22.963 9.40799V18.11H20.455V9.33199C20.455 8.47066 20.664 7.69799 21.082 7.01399C21.4873 6.34266 22.051 5.81699 22.773 5.43699C23.4823 5.06966 24.2867 4.88599 25.186 4.88599Z fillwhite>/path>path dM21.5 13.5H28.5V15.5H25H21.5V13.5Z fillwhite>/path>/g>defs>clipPath idclip0_121_23>rect width39 height40 fillwhite>/rect>/clipPath>/defs>/svg>/div>/a>/div>nav classhidden md:flex text-center ml-15% basis-full md:basis-auto>ul classm-0 p-0 list-none inline-flex relative top-5px sm:justify-around>li>a styleposition:relative classcursor-pointer primary-font href/>span classnavigation_navigation__G3EeK font-semibold text-black navigation_navigationActive__Cefvt>Home/span>/a>/li>li>a styleposition:relative classcursor-pointer primary-font href/blog>span classnavigation_navigation__G3EeK font-semibold text-gray-900>Posts/span>/a>/li>li>a styleposition:relative classcursor-pointer primary-font href/snippets>span classnavigation_navigation__G3EeK font-semibold text-gray-900>Snippets/span>/a>/li>li>a styleposition:relative classcursor-pointer primary-font href/about>span classnavigation_navigation__G3EeK font-semibold text-gray-900>About/span>/a>/li>/ul>/nav>div classflex flex-row justify-between min-w-40px visible md:hidden>button classmobile-menu_burger__oGD28 visible md:hidden aria-labelToggle menu typebutton>svg classh-5 w-5 absolute text-gray-900 dark:text-gray-100 width20 height20 viewBox0 0 20 20 fillnone data-hidefalse>path dM2.5 7.5H17.5 strokecurrentColor stroke-width1.5 stroke-linecapround stroke-linejoinround>/path>path dM2.5 12.5H17.5 strokecurrentColor stroke-width1.5 stroke-linecapround stroke-linejoinround>/path>/svg>svg classh-5 w-5 absolute text-gray-900 dark:text-gray-100 viewBox0 0 24 24 width24 height24 strokecurrentColor stroke-width1.5 stroke-linecapround stroke-linejoinround fillnone shape-renderinggeometricPrecision data-hidetrue>path dM18 6L6 18>/path>path dM6 6l12 12>/path>/svg>/button>/div>/div>/div>/div>div classflex flex-col justify-center relative z-10>div classmax-w-65rem mx-auto pb-16 relative w-full>div classapp-content app-content--bold vt-updateauto>div classrelative>div classflex flex-col md:flex-row relative z-10 md:mb-0 mb-4>div classflex flex-row w-full relative md:p-10 p-6 pt-10 relative>div classw-full flex flex-col md:pt-20 pt-0>h1 classtext-3xl md:text-5xl tracking-wide mb-3 text-black styleopacity:0;transform:translateY(30px) translateZ(0)>Thoughts br class/>Code br class/>Coffee/h1>p classtext-gray-800 dark:text-gray-400 md:mb-16 mb-8 styleopacity:0;transform:translateY(30px) translateZ(0)>I'm Raman Ramanouski, a Senior Frontend Engineer who turns caffeine into fast, secure, and scalable web apps. br/>This is my digital home: a space to share what I’ve learned, what I’m building, and the ideas shaping how we engineer the modern web./p>hr classblock md:hidden text-black/>/div>/div>div classgroup cursor-pointer w-full relative hero-post md:pt-10 md:py-0 px-6 py-6 styleopacity:0;transform:translateY(30px) translateZ(0)>div classmb-2 flex>div classoverflow-hidden duration-300 ease-in-out relative h-full object-cover w-full vt-nameblog-image-nextjs-environment-variables vt-updateauto vt-shareauto>img altMain post image width897 height544 decodingasync data-nimg1 classduration-700 ease-in-out rounded-md stylecolor:transparent;filter:grayscale(80%);object-fit:cover;min-width:100%;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url("data:image/svg+xml;charsetutf-8,%3Csvg xmlns'http://www.w3.org/2000/svg' viewBox'0 0 897 544'%3E%3Cfilter id'b' color-interpolation-filters'sRGB'%3E%3CfeGaussianBlur stdDeviation'20'/%3E%3CfeColorMatrix values'1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result's'/%3E%3CfeFlood x'0' y'0' width'100%25' height'100%25'/%3E%3CfeComposite operator'out' in's'/%3E%3CfeComposite in2'SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation'20'/%3E%3C/filter%3E%3Cimage width'100%25' height'100%25' x'0' y'0' preserveAspectRatio'none' style'filter: url(%23b);' href'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAACXBIWXMAAAsTAAALEwEAmpwYAAAALUlEQVR4nAEiAN3/ADo5sv9oVNT+tn///0EXs+QAAABX/1A6qf7U+f//m6f/5D1wFExBXchjAAAAAElFTkSuQmCC'/%3E%3C/svg%3E") sizes520px srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png 920w srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/nextjs-env-variables/main.png/>/div>/div>h1 classtext-lg font-semibold underline underline-offset-4 vt-nameblog-title-nextjs-environment-variables vt-updateauto vt-shareauto>span data-br_R_1adanntb_ data-brr1 styledisplay:inline-block;vertical-align:top;text-decoration:inherit>Next.js Environment Variables: The Missing Guide/span>script>self.__wrap_b(a,b,c)>{let d(cc||document.querySelector(`data-br${a}`)).parentElement,ea>c.style.maxWidtha+px;c.style.maxWidth;let fd.clientWidth,gd.clientHeight,hf/2-.25,if+.5,j;if(f){for(;h+1i;)e(jMath.round((h+i)/2)),d.clientHeightg?ij:hj;e(i*b+f*(1-b))}c.__wrap_o||undefined!typeof ResizeObserver&&(c.__wrap_onew ResizeObserver(()>{self.__wrap_b(0,+c.dataset.brr,c)})).observe(d)};self.__wrap_b(_R_1adanntb_,1)/script>/h1>div classtext-md mt-2 text-gray-800 mb-3 line-clamp-3 stylemask-image:linear-gradient(0deg,transparent,black 80px);overflow:hidden;max-height:100px>Next.js environment variables fail silently - unless you force them to fail early. You can think of it as a loaded gun on the wall: it may sit there quietly for weeks, until one day it goes off in production./div>a classtext-primary flex space-x-4 focus:outline-none focus:bg-#e5e5e5 mt-3 ml--0.5rem cursor-pointer group-hover:bg-#e5e5e5 rounded-md px-2 py-1 max-w-215px hrefblog/nextjs-environment-variables>span classtext-md mt-2px>Read More/span>span classflex items-center>svg width73 height8 viewBox0 0 73 8 fillnone xmlnshttp://www.w3.org/2000/svg>path dM72.3536 4.35355C72.5488 4.15829 72.5488 3.84171 72.3536 3.64645L69.1716 0.464466C68.9763 0.269204 68.6597 0.269204 68.4645 0.464466C68.2692 0.659728 68.2692 0.976311 68.4645 1.17157L71.2929 4L68.4645 6.82843C68.2692 7.02369 68.2692 7.34027 68.4645 7.53553C68.6597 7.7308 68.9763 7.7308 69.1716 7.53553L72.3536 4.35355ZM72 3.5L-3.33786e-06 3.5V4.5L72 4.5V3.5Z fillblack>/path>/svg>/span>/a>/div>/div>div classh-85px sm:flex relative z-10 md:flex hidden>div classw-20 min-h-fit>/div>div classw-full relative p-10 min-h-20px>div classabsolute bottom-40px left-40px>div classflex flex-row gap-2>svg width128 height10 viewBox0 0 128 10 fillnone xmlnshttp://www.w3.org/2000/svg>rect width5 height5 rx5 fill#c9b3dc>/rect>rect width5 height5 rx5 fill#c9b3dc>/rect>rect width5 height5 rx5 fill#c9b3dc>/rect>/svg>/div>/div>div classabsolute bottom-40px right-60px>div classflex flex-row gap-2>svg width128 height10 viewBox0 0 128 10 fillnone xmlnshttp://www.w3.org/2000/svg>rect width5 height5 rx5 fill#c9b3dc>/rect>rect width5 height5 rx5 fill#c9b3dc>/rect>rect width5 height5 rx5 fill#c9b3dc>/rect>/svg>/div>/div>/div>/div>/div>/div>div classrelative flex flex-col layout-full ml-auto mr-auto max-layout-900px>div classrelative>div classh-120px w-full md:block hidden>/div>div classrelative pl-10 ml-0 pt-4 md:flex hidden styleopacity:0>div classabsolute text-md mt--55px primary-font>Recent Posts:/div>/div>/div>div styleopacity:0>div classgrid md:grid-cols-2 grid-cols-1 gap-5 layout-full md:p-10 px-4 relative pt-8 mt--14px relative>a classw-full href/blog/story-of-ratu-dev>div classgroup flex w-full flex-col md:p-4 p-0 relative rounded-md md:bg-transparent bg-var(--bg-card-small) bg-linear-(--bg-card-small) hover:bg-white cursor-pointer transition ease-in-out duration-200 stylebox-shadow:0 0 0 1px hsl(0 0% 93.0%)>div classz-10>div classrelative md:p-0 p-3 z>div classoverflow-hidden duration-300 ease-in-out relative h-full object-cover w-full vt-nameblog-image-story-of-ratu-dev vt-updateauto vt-shareauto>img altMain post image loadinglazy width1848 height1231 decodingasync data-nimg1 classduration-700 ease-in-out rounded-none stylecolor:transparent;filter:grayscale(80%);object-fit:cover;min-width:100% sizes520px srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png 920w srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/story-of-ratu-dev/main.png/>/div>/div>div classtext-xs md:my-2 md:px-0 px-3>span title22 Aug 2025>Aug 2025/span> • span>3 min read/span>/div>div classmt-4 mr-auto md:pr-2 md:p-0 px-3>h4 classtext-lg mb-2 font-semibold vt-nameblog-title-story-of-ratu-dev vt-updateauto vt-shareauto>Perfect Is the Enemy of Done - The Story of ratu.dev/h4>div classtext-sm text-black-800 mb-3 line-clamp-4>After 10 years on the web and dozens of projects, it still took me 3 years to build my own digital home - ratu.dev. It's basically a monument to my procrastination, and to idealism/div>/div>/div>div classcard_cardBg___JYTx rounded-md>/div>/div>/a>a classw-full href/blog/mastering-nodejs-scripting>div classgroup flex w-full flex-col md:p-4 p-0 relative rounded-md md:bg-transparent bg-var(--bg-card-small) bg-linear-(--bg-card-small) hover:bg-white cursor-pointer transition ease-in-out duration-200 stylebox-shadow:0 0 0 1px hsl(0 0% 93.0%)>div classz-10>div classrelative md:p-0 p-3 z>div classoverflow-hidden duration-300 ease-in-out relative h-full object-cover w-full vt-nameblog-image-mastering-nodejs-scripting vt-updateauto vt-shareauto>img altMain post image loadinglazy width1667 height1141 decodingasync data-nimg1 classduration-700 ease-in-out rounded-none stylecolor:transparent;filter:grayscale(80%);object-fit:cover;min-width:100% sizes520px srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/scripting/main.png 920w srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/posts/scripting/main.png/>/div>/div>div classtext-xs md:my-2 md:px-0 px-3>span title30 Aug 2025>Aug 2025/span> • span>26 min read/span>/div>div classmt-4 mr-auto md:pr-2 md:p-0 px-3>h4 classtext-lg mb-2 font-semibold vt-nameblog-title-mastering-nodejs-scripting vt-updateauto vt-shareauto>Mastering Node.js scripting: Tools/CLI/AI/Steroids/h4>div classtext-sm text-black-800 mb-3 line-clamp-4 stylemask-image:linear-gradient(0deg,transparent,black 80px);overflow:hidden;max-height:100px>Scripting isn't about perfection — it's about saving time. It should be pragmatic, fast, and never something you get stuck on. Over the past 10 years, I went from barely seeing the point of scripting to writing quick scripts in minutes — scripts that save time, and that time stack up over the years./div>/div>/div>div classcard_cardBg___JYTx rounded-md>/div>/div>/a>/div>div classgrid md:grid-cols-2 grid-cols-1 gap-5 layout-full md:p-10 px-4 relative pt-8 relative>a classw-full href/snippets/nodejs-cheatsheet>div classgroup flex w-full flex-col md:p-4 p-0 relative rounded-md md:bg-transparent bg-var(--bg-card-small) bg-linear-(--bg-card-small) hover:bg-white cursor-pointer transition ease-in-out duration-200 stylebox-shadow:0 0 0 1px hsl(0 0% 93.0%)>div classz-10>div classrelative md:p-0 p-3 z>div classoverflow-hidden duration-300 ease-in-out relative h-full object-cover w-full vt-nameblog-image-nodejs-cheatsheet vt-updateauto vt-shareauto>img altMain post image loadinglazy width896 height347 decodingasync data-nimg1 classduration-700 ease-in-out rounded-none stylecolor:transparent;filter:grayscale(80%);object-fit:cover;min-width:100% sizes520px srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png 920w srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/nodejs-cheatsheet/main.png/>/div>/div>div classmt-4 mr-auto md:pr-2 md:p-0 px-3>h4 classtext-lg mb-2 font-semibold vt-nameblog-title-nodejs-cheatsheet vt-updateauto vt-shareauto>Node.js Scripting Cheatsheet (Battle Tested)/h4>div classtext-sm text-black-800 mb-3 line-clamp-4>This cheatsheet is a collection of battle-tested Node.js snippets I use for scripting, automation, and everyday backend hacks. Copy, paste, and adapt — no fluff, just code that works./div>/div>/div>div classcard_cardBg___JYTx rounded-md>/div>/div>/a>a classw-full href/snippets/google-sheets-data-saving-nodejs-nextjs-snippet>div classgroup flex w-full flex-col md:p-4 p-0 relative rounded-md md:bg-transparent bg-var(--bg-card-small) bg-linear-(--bg-card-small) hover:bg-white cursor-pointer transition ease-in-out duration-200 stylebox-shadow:0 0 0 1px hsl(0 0% 93.0%)>div classz-10>div classrelative md:p-0 p-3 z>div classoverflow-hidden duration-300 ease-in-out relative h-full object-cover w-full vt-nameblog-image-google-sheets-data-saving-nodejs-nextjs-snippet vt-updateauto vt-shareauto>img altMain post image loadinglazy width896 height347 decodingasync data-nimg1 classduration-700 ease-in-out rounded-none stylecolor:transparent;filter:grayscale(80%);object-fit:cover;min-width:100% sizes520px srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png 920w srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/gsheet/main.png/>/div>/div>div classmt-4 mr-auto md:pr-2 md:p-0 px-3>h4 classtext-lg mb-2 font-semibold vt-nameblog-title-google-sheets-data-saving-nodejs-nextjs-snippet vt-updateauto vt-shareauto>Save to Google Sheets with Nodejs/Nextjs/h4>div classtext-sm text-black-800 mb-3 line-clamp-4>Learn how to use Google Sheets as a simple backend for your Node.js/Next.js app with minimal setup. Perfect for quick prototypes and easy data management./div>/div>/div>div classcard_cardBg___JYTx rounded-md>/div>/div>/a>a classw-full href/snippets/simple-password-protection-for-a-next-js-app>div classgroup flex w-full flex-col md:p-4 p-0 relative rounded-md md:bg-transparent bg-var(--bg-card-small) bg-linear-(--bg-card-small) hover:bg-white cursor-pointer transition ease-in-out duration-200 stylebox-shadow:0 0 0 1px hsl(0 0% 93.0%)>div classz-10>div classrelative md:p-0 p-3 z>div classoverflow-hidden duration-300 ease-in-out relative h-full object-cover w-full vt-nameblog-image-simple-password-protection-for-a-next-js-app vt-updateauto vt-shareauto>img altMain post image loadinglazy width896 height360 decodingasync data-nimg1 classduration-700 ease-in-out rounded-none stylecolor:transparent;filter:grayscale(80%);object-fit:cover;min-width:100% sizes520px srcSethttps://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width260,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 260w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width520,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 520w, https://cloudflare.ratu.dev/cdn-cgi/image/width768,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 768w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 920w, https://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png 920w srchttps://cloudflare.ratu.dev/cdn-cgi/image/width920,formatauto,fitscale-down,quality95/images/snippets/password-protection/main.png/>/div>/div>div classmt-4 mr-auto md:pr-2 md:p-0 px-3>h4 classtext-lg mb-2 font-semibold vt-nameblog-title-simple-password-protection-for-a-next-js-app vt-updateauto vt-shareauto>Simple password protection for a Next.js app/h4>div classtext-sm text-black-800 mb-3 line-clamp-4>Secure pages in a Next.js app with password protection with middleware and WWW-Authenticate: no user database or external auth service, no UI required./div>/div>/div>div classcard_cardBg___JYTx rounded-md>/div>/div>/a>/div>/div>/div>div classmd:ml-10px relative>div classrelative flex flex-col layout-full ml-auto mr-auto max-layout-900px md:px-10 px-4>form>div classmd:p-5 md:px-10 p-0 md:mt-20 mt-8 overflow-hidden relative>div class styletransition:.3s all>div classtext-md>Shall I keep you in the loop?/div>div classtext-gray-700 text-xs mb-2 max-w-full>Includes articles, early access to tools, and lots of other cool stuff./div>/div>div classrelative max-w-600px mb-1>input typeemail classflex border-input shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm h-50px border w-full p-2 pl-3 bg-gray-50 rounded-md text-sm required placeholderlethim@cook.com/>button classjustify-center gap-2 whitespace-nowrap font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 &_svg:pointer-events-none &_svg:size-4 &_svg:shrink-0 border-input shadow-sm hover:bg-accent hover:text-accent-foreground focus:bg-primary-12 focus:outline-primary-12 text-sm text-black bg-white h-35px rounded-md border p-2 absolute top-7.5px right-7.5px flex items-center typesubmit>Subscribe/button>/div>div classtext-xs styletransition:.3s all>Sent out every two months. No spam./div>/div>/form>/div>/div>!--$-->!--/$-->/div>footer classflex flex-col justify-center>div classmax-w-60rem mx-auto w-full relative h-75px>div classapp-content-bottom>/div>/div>div classflex flex-row justify-between max-w-60rem mx-auto w-full px-5>/div>div classw-full min-h-100px md:pb-10 bg-#fafafa md:px-5 px-4 pb-6>div classmax-w-45rem mx-auto w-full>div classflex gap-10 justify-between pb-16 grid-cols-4 text-sm pt-5>div classmd:flex hidden max-w-300px text-xs>ul classflex gap-2>li classmin-h-32px text-gray-700 hover:text-gray-950>a classrounded font-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#333 hocus:bg-#ebebeb titleGitHub target_blank relnoopener noreferrer hrefhttps://github.com/ra2dev/>svg viewBox0 0 24 24 rolepresentation classfill-inherit transition-colors size-5.5 aria-hiddentrue styleheight:24px>path fillblack dM12 2C6.3 2 1.8 6.6 1.8 12.2c0 4.5 2.9 8.4 7 9.7.5.1.7-.2.7-.5v-1.7c-2.9.7-3.5-1.3-3.5-1.3-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.6 1.1 1.6 1.1.9 1.6 2.4 1.1 3 .9.1-.7.4-1.1.6-1.4-2.3-.3-4.7-1.1-4.7-5 0-1.1.4-2 1.1-2.8-.2-.4-.5-1.5 0-2.8 0 0 .9-.3 2.8 1 .8-.2 1.7-.3 2.6-.3s1.8.1 2.6.3c2-1.3 2.8-1 2.8-1 .6 1.4.2 2.4.1 2.7.7.7 1.1 1.6 1.1 2.8 0 3.9-2.4 4.8-4.7 5 .4.3.7.9.7 1.9v2.8c0 .3.2.6.7.5 4.1-1.4 7-5.2 7-9.7C22.2 6.6 17.7 2 12 2z>/path>/svg>/a>/li>li classmin-h-32px text-gray-700 hover:text-gray-950>a classfont-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#0C66C2 hocus:bg-#e7f0f9 dark:hocus:bg-#031f3a titleLinkedIn target_blank relnoopener noreferrer hrefhttps://www.linkedin.com/in/ratu-dev/>svg viewBox0 0 24 24 rolepresentation classfill-inherit transition-colors size-5.5 aria-hiddentrue styleheight:24px>path classfill-current dM21 21v-7.2c0-2.4-2-4.4-4.4-4.4-1.1 0-2.5.7-3.1 1.8V9.7H9.7V21h3.8v-6.7c0-1 .8-1.9 1.9-1.9 1 0 1.9.8 1.9 1.9V21H21M5.3 7.6c1.3 0 2.3-1 2.3-2.3C7.6 4 6.5 3 5.3 3 4 3 3 4 3 5.3c0 1.2 1 2.3 2.3 2.3M7.2 21V9.7H3.4V21h3.8z>/path>/svg>/a>/li>li classmin-h-32px text-gray-700 hover:text-gray-950>a classfont-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#356AC4 hocus:dark:text-#5591f5 hocus:bg-#ecf3fe dark:hocus:bg-#142849 titleGet in Touch hrefmailto:me@ratu.dev>svg viewBox0 0 24 24 rolepresentation classfill-inherit transition-colors size-5.5 mt-3px aria-hiddentrue styleheight:24px>path classfill-current dm20 8-8 5-8-5V6l8 5 8-5m0-2H4c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2Z>/path>/svg>/a>/li>li classmin-h-32px text-gray-700 hover:text-gray-950>a classtext-25px rounded font-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#333 hocus:bg-#ebebeb titleGitHub target_blank relnoopener noreferrer hrefhttps://x.com/ratwodev/>𝕏/a>/li>/ul>/div>div classflex flex-col space-y-4>a classhover:underline href/>Home/a>a classhover:underline href/about>About/a>/div>div classflex flex-col space-y-4>a classhover:underline href/blog>Blog/a>a classhover:underline href/snippets>Snippets/a>/div>div classflex flex-col space-y-4>a target_blank relnoopener noreferrer hrefhttps://cloud.umami.is/share/RBbzQtqQltIEJrHp/ratu.dev classhover:underline underline-offset-2 font-semibold flex gap-2 items-center>svg xmlnshttp://www.w3.org/2000/svg width24 height20 viewBox0 0 24 24 fillnone strokecurrentColor stroke-width2 stroke-linecapround stroke-linejoinround classlucide lucide-chart-no-axes-combined aria-hiddentrue>path dM12 16v5>/path>path dM16 14v7>/path>path dM20 10v11>/path>path dm22 3-8.646 8.646a.5.5 0 0 1-.708 0L9.354 8.354a.5.5 0 0 0-.707 0L2 15>/path>path dM4 18v3>/path>path dM8 14v7>/path>/svg>div>Analytic/div>/a>/div>/div>div classrelative>span classtext-xs primary-font>Crafted with ❤️ by!-- --> a hrefhttps://github.com/ra2dev/ target_blank>Raman Ramanouski/a>/span>/div>/div>/div>/footer>/div>/main>script src/_next/static/chunks/webpack-84ab9ee953850d3a.js id_R_ async>/script>script>(self.__next_fself.__next_f||).push(0)/script>script>self.__next_f.push(1,1:\$Sreact.fragment\\n2:I80901,\440\,\static/chunks/440-a720412ecf546db4.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\177\,\static/chunks/app/layout-2b304fe192248531.js\,\\\n3:I9480,\440\,\static/chunks/440-a720412ecf546db4.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\177\,\static/chunks/app/layout-2b304fe192248531.js\,\LayoutAnimation\\n4:I70740,\440\,\static/chunks/440-a720412ecf546db4.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\177\,\static/chunks/app/layout-2b304fe192248531.js\,\Navigation\\n5:I70441,\440\,\static/chunks/440-a720412ecf546db4.js\,\713\,\static/chunks/713-a98e84a52def2dba.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\908\,\static/chunks/908-64a17f68de53ce6d.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\183\,\static/chunks/183-206a2249f9a2c3ad.js\,\588\,\static/chunks/588-d881c5c2c5e86f7b.js\,\974\,\static/chunks/app/page-d7607bcac0e5d501.js\,\SmartLineWrapperProvider\\n6:I96533,,\\\n7:I3405,\713\,\static/chunks/713-a98e84a52def2dba.js\,\39\,\static/chunks/app/error-38231a477418fed8.js\,\default\\n8:I79569,,\\\n9:I3144,\440\,\static/chunks/440-a720412ecf546db4.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\177\,\static/chunks/app/layout-2b304fe192248531.js\,\\\n13:I30871,,\\\n:HL\/_next/static/media/031a93a156d22825-s.p.woff2\,\font\,{\crossOrigin\:\\,\type\:\font/woff2\}\n:HL\/_next/static/media/9cf9c6e84ed13b5e-s.p.woff2\,\font\,{\crossOrigin\:\\,\type\:\font/woff2\}\n:HL\/_next/static/css/56aca9a88ce3f35c.css\,\style\\n:HL\/_next/static/css/2cceed9f73df3333.css\,\style\\n)/script>script>self.__next_f.push(1,0:{\P\:null,\b\:\ZvXlnZCeXv2FqHXdbzTf2\,\p\:\\,\c\:\\,\\,\i\:false,\f\:\\,{\children\:\__PAGE__\,{}},\$undefined\,\$undefined\,true,\\,\$\,\$1\,\c\,{\children\:\$\,\link\,\0\,{\rel\:\stylesheet\,\href\:\/_next/static/css/56aca9a88ce3f35c.css\,\precedence\:\next\,\crossOrigin\:\$undefined\,\nonce\:\$undefined\},\$\,\html\,null,{\lang\:\en\,\className\:\light\,\children\:\$\,\head\,null,{\children\:\$\,\meta\,null,{\charSet\:\utf-8\},\$\,\meta\,null,{\name\:\viewport\,\content\:\widthdevice-width, initial-scale1 maximum-scale1\},\$\,\link\,null,{\rel\:\sitemap\,\href\:\/sitemap.xml\},\$\,\link\,null,{\rel\:\icon\,\href\:\/favicon.ico\},\$\,\link\,null,{\rel\:\apple-touch-icon\,\href\:\/apple-touch-icon.png\},\$\,\link\,null,{\rel\:\preconnect\,\href\:\https://api-gateway.umami.dev\},\$\,\$L2\,null,{\defer\:true,\src\:\https://cloud.umami.is/script.js\,\data-website-id\:\a47b352d-a91d-4573-8ce0-7e1ccc90c9e0\}},\$\,\body\,null,{\className\:\__variable_e95cc6 __variable_622c96\,\children\:\$\,\main\,null,{\children\:\$\,\$L3\,null,{},\$\,\div\,null,{\id\:\mobile-nav-portal-target\},null,\$\,\$L4\,null,{},\$\,\$L5\,null,{\children\:\$\,\div\,null,{\className\:\flex flex-col justify-center relative z-10\,\children\:\$\,\div\,null,{\className\:\max-w-65rem mx-auto pb-16 relative w-full\,\children\:\$\,\$L6\,null,{\parallelRouterKey\:\children\,\error\:\$7\,\errorStyles\:,\errorScripts\:,\template\:\$\,\$L8\,null,{},\templateStyles\:\$undefined\,\templateScripts\:\$undefined\,\notFound\:\$\,\div\,null,{\className\:\flex flex-col items-center justify-center min-h-65vh px-4\,\children\:\$\,\h1\,null,{\className\:\text-4xl font-bold mb-4\,\children\:\404\},\$\,\h2\,null,{\className\:\text-2xl font-medium mb-4\,\children\:\Page Not Found\},\$\,\p\,null,{\className\:\mb-6 text-center\,\children\:\Sorry, the page you are looking for does not exist.\},\$\,\$L9\,null,{\href\:\/\,\className\:\px-4 py-2 text-black rounded transition-colors\,\children\:\$\,\button\,null,{\className\:\inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 \u0026_svg:pointer-events-none \u0026_svg:size-4 \u0026_svg:shrink-0 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2\,\ref\:\$undefined\,\children\:\Return Home\}}},,\forbidden\:\$undefined\,\unauthorized\:\$undefined\}},\$\,\footer\,null,{\className\:\flex flex-col justify-center\,\children\:\$\,\div\,null,{\className\:\max-w-60rem mx-auto w-full relative h-75px\,\children\:\$\,\div\,null,{\className\:\app-content-bottom\}},\$\,\div\,null,{\className\:\flex flex-row justify-between max-w-60rem mx-auto w-full px-5\,\children\:null},\$\,\div\,null,{\className\:\w-full min-h-100px md:pb-10 bg-#fafafa md:px-5 px-4 pb-6\,\children\:\$\,\div\,null,{\className\:\max-w-45rem mx-auto w-full\,\children\:\$\,\div\,null,{\className\:\flex gap-10 justify-between pb-16 grid-cols-4 text-sm pt-5\,\children\:\$\,\div\,null,{\className\:\md:flex hidden max-w-300px text-xs\,\children\:\$\,\ul\,null,{\className\:\flex gap-2\,\children\:\$\,\li\,null,{\className\:\min-h-32px text-gray-700 hover:text-gray-950\,\children\:\$\,\a\,null,{\className\:\rounded font-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#333 hocus:bg-#ebebeb\,\title\:\GitHub\,\target\:\_blank\,\rel\:\noopener noreferrer\,\href\:\https://github.com/ra2dev/\,\children\:\$\,\svg\,null,{\viewBox\:\0 0 24 24\,\role\:\presentation\,\className\:\fill-inherit transition-colors size-5.5\,\aria-hidden\:\true\,\style\:{\height\:\24px\},\children\:\$\,\path\,null,{\fill\:\black\,\d\:\M12 2C6.3 2 1.8 6.6 1.8 12.2c0 4.5 2.9 8.4 7 9.7.5.1.7-.2.7-.5v-1.7c-2.9.7-3.5-1.3-3.5-1.3-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.6 1.1 1.6 1.1.9 1.6 2.4 1.1 3 .9.1-.7.4-1.1.6-1.4-2.3-.3-4.7-1.1-4.7-5 0-1.1.4-2 1.1-2.8-.2-.4-.5-1.5 0-2.8 0 0 .9-.3 2.8 1 .8-.2 1.7-.3 2.6-.3s1.8.1 2.6.3c2-1.3 2.8-1 2.8-1 .6 1.4.2 2.4.1 2.7.7.7 1.1 1.6 1.1 2.8 0 3.9-2.4 4.8-4.7 5 .4.3.7.9.7 1.9v2.8c0 .3.2.6.7.5 4.1-1.4 7-5.2 7-9.7C22.2 6.6 17.7 2 12 2z\}}}},\$La\,\$Lb\,\$Lc\}},\$Ld\,\$Le\,\$Lf\},\$L10\}}}}}}}}},{\children\:\__PAGE__\,\$L11\,{},null,false},null,false,\$L12\,false,\m\:\$undefined\,\G\:\$13\,,\s\:false,\S\:true}\n)/script>script>self.__next_f.push(1,15:I61736,,\OutletBoundary\\n17:I39009,,\AsyncMetadataOutlet\\n19:I61736,,\ViewportBoundary\\n1b:I61736,,\MetadataBoundary\\n1c:\$Sreact.suspense\\n)/script>script>self.__next_f.push(1,a:\$\,\li\,null,{\className\:\min-h-32px text-gray-700 hover:text-gray-950\,\children\:\$\,\a\,null,{\className\:\font-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#0C66C2 hocus:bg-#e7f0f9 dark:hocus:bg-#031f3a\,\title\:\LinkedIn\,\target\:\_blank\,\rel\:\noopener noreferrer\,\href\:\https://www.linkedin.com/in/ratu-dev/\,\children\:\$\,\svg\,null,{\viewBox\:\0 0 24 24\,\role\:\presentation\,\className\:\fill-inherit transition-colors size-5.5\,\aria-hidden\:\true\,\style\:{\height\:\24px\},\children\:\$\,\path\,null,{\className\:\fill-current\,\d\:\M21 21v-7.2c0-2.4-2-4.4-4.4-4.4-1.1 0-2.5.7-3.1 1.8V9.7H9.7V21h3.8v-6.7c0-1 .8-1.9 1.9-1.9 1 0 1.9.8 1.9 1.9V21H21M5.3 7.6c1.3 0 2.3-1 2.3-2.3C7.6 4 6.5 3 5.3 3 4 3 3 4 3 5.3c0 1.2 1 2.3 2.3 2.3M7.2 21V9.7H3.4V21h3.8z\}}}}\n)/script>script>self.__next_f.push(1,b:\$\,\li\,null,{\className\:\min-h-32px text-gray-700 hover:text-gray-950\,\children\:\$\,\a\,null,{\className\:\font-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#356AC4 hocus:dark:text-#5591f5 hocus:bg-#ecf3fe dark:hocus:bg-#142849\,\title\:\Get in Touch\,\href\:\mailto:me@ratu.dev\,\children\:\$\,\svg\,null,{\viewBox\:\0 0 24 24\,\role\:\presentation\,\className\:\fill-inherit transition-colors size-5.5 mt-3px\,\aria-hidden\:\true\,\style\:{\height\:\24px\},\children\:\$\,\path\,null,{\className\:\fill-current\,\d\:\m20 8-8 5-8-5V6l8 5 8-5m0-2H4c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2Z\}}}}\n)/script>script>self.__next_f.push(1,c:\$\,\li\,null,{\className\:\min-h-32px text-gray-700 hover:text-gray-950\,\children\:\$\,\a\,null,{\className\:\text-25px rounded font-medium self-start flex items-center justify-center h-2.75rem w-2.75rem p-2 rounded-1.5 no-underline transition-colors text-black bg-transparent hocus:text-#333 hocus:bg-#ebebeb\,\title\:\GitHub\,\target\:\_blank\,\rel\:\noopener noreferrer\,\href\:\https://x.com/ratwodev/\,\children\:\𝕏\}}\nd:\$\,\div\,null,{\className\:\flex flex-col space-y-4\,\children\:\$\,\$L9\,null,{\href\:\/\,\className\:\hover:underline\,\children\:\Home\},\$\,\$L9\,null,{\href\:\/about/\,\className\:\hover:underline\,\children\:\About\}}\ne:\$\,\div\,null,{\className\:\flex flex-col space-y-4\,\children\:\$\,\$L9\,null,{\href\:\/blog/\,\className\:\hover:underline\,\children\:\Blog\},\$\,\$L9\,null,{\href\:\/snippets/\,\className\:\hover:underline\,\children\:\Snippets\}}\n)/script>script>self.__next_f.push(1,f:\$\,\div\,null,{\className\:\flex flex-col space-y-4\,\children\:\$\,\a\,null,{\target\:\_blank\,\rel\:\noopener noreferrer\,\href\:\https://cloud.umami.is/share/RBbzQtqQltIEJrHp/ratu.dev\,\className\:\hover:underline underline-offset-2 font-semibold flex gap-2 items-center\,\children\:\$\,\svg\,null,{\ref\:\$undefined\,\xmlns\:\http://www.w3.org/2000/svg\,\width\:24,\height\:20,\viewBox\:\0 0 24 24\,\fill\:\none\,\stroke\:\currentColor\,\strokeWidth\:2,\strokeLinecap\:\round\,\strokeLinejoin\:\round\,\className\:\lucide lucide-chart-no-axes-combined\,\aria-hidden\:\true\,\children\:\$\,\path\,\zza2cw\,{\d\:\M12 16v5\},\$\,\path\,\1g90b9\,{\d\:\M16 14v7\},\$\,\path\,\1iqoj0\,{\d\:\M20 10v11\},\$\,\path\,\1fw8x9\,{\d\:\m22 3-8.646 8.646a.5.5 0 0 1-.708 0L9.354 8.354a.5.5 0 0 0-.707 0L2 15\},\$\,\path\,\1yp0dc\,{\d\:\M4 18v3\},\$\,\path\,\n3cwzv\,{\d\:\M8 14v7\},\$undefined\},\$\,\div\,null,{\children\:\Analytic\}}}\n)/script>script>self.__next_f.push(1,10:\$\,\div\,null,{\className\:\relative\,\children\:\$\,\span\,null,{\className\:\text-xs primary-font\,\children\:\Crafted with ❤️ by\,\ \,\$\,\a\,null,{\href\:\https://github.com/ra2dev/\,\target\:\_blank\,\children\:\Raman Ramanouski\}}}\n11:\$\,\$1\,\c\,{\children\:\$L14\,\$\,\link\,\0\,{\rel\:\stylesheet\,\href\:\/_next/static/css/2cceed9f73df3333.css\,\precedence\:\next\,\crossOrigin\:\$undefined\,\nonce\:\$undefined\},\$\,\$L15\,null,{\children\:\$L16\,\$\,\$L17\,null,{\promise\:\$@18\}}}\n12:\$\,\$1\,\h\,{\children\:null,\$\,\$L19\,null,{\children\:\$L1a\},\$\,\meta\,null,{\name\:\next-size-adjust\,\content\:\\},\$\,\$L1b\,null,{\children\:\$\,\div\,null,{\hidden\:true,\children\:\$\,\$1c\,null,{\fallback\:null,\children\:\$L1d\}}}}\n)/script>script>self.__next_f.push(1,1a:\$\,\meta\,\0\,{\charSet\:\utf-8\},\$\,\meta\,\1\,{\name\:\viewport\,\content\:\widthdevice-width, initial-scale1\}\n16:null\n)/script>script>self.__next_f.push(1,18:{\metadata\:\$\,\title\,\0\,{\children\:\Home | Raman Ramanouski | ratu.dev\},\$\,\meta\,\1\,{\name\:\description\,\content\:\Personal blog | Raman Ramanouski - portfolio overview, including links to blog posts, projects, snippets\},\$\,\meta\,\2\,{\name\:\author\,\content\:\Raman Ramanouski\},\$\,\meta\,\3\,{\name\:\creator\,\content\:\Raman Ramanouski\},\$\,\meta\,\4\,{\property\:\og:title\,\content\:\Home | Raman Ramanouski | ratu.dev\},\$\,\meta\,\5\,{\property\:\og:description\,\content\:\Personal blog | Raman Ramanouski - portfolio overview, including links to blog posts, projects, snippets\},\$\,\meta\,\6\,{\property\:\og:image\,\content\:\https://ratu.dev/images/opengraph-image.png\},\$\,\meta\,\7\,{\name\:\twitter:card\,\content\:\summary_large_image\},\$\,\meta\,\8\,{\name\:\twitter:title\,\content\:\Home | Raman Ramanouski | ratu.dev\},\$\,\meta\,\9\,{\name\:\twitter:description\,\content\:\Personal blog | Raman Ramanouski - portfolio overview, including links to blog posts, projects, snippets\},\$\,\meta\,\10\,{\name\:\twitter:image\,\content\:\https://ratu.dev/images/opengraph-image.png\},\error\:null,\digest\:\$undefined\}\n)/script>script>self.__next_f.push(1,1d:\$18:metadata\\n)/script>script>self.__next_f.push(1,1e:I61190,\440\,\static/chunks/440-a720412ecf546db4.js\,\713\,\static/chunks/713-a98e84a52def2dba.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\908\,\static/chunks/908-64a17f68de53ce6d.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\183\,\static/chunks/183-206a2249f9a2c3ad.js\,\588\,\static/chunks/588-d881c5c2c5e86f7b.js\,\974\,\static/chunks/app/page-d7607bcac0e5d501.js\,\HeroHome\\n1f:I67051,\440\,\static/chunks/440-a720412ecf546db4.js\,\713\,\static/chunks/713-a98e84a52def2dba.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\908\,\static/chunks/908-64a17f68de53ce6d.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\183\,\static/chunks/183-206a2249f9a2c3ad.js\,\588\,\static/chunks/588-d881c5c2c5e86f7b.js\,\974\,\static/chunks/app/page-d7607bcac0e5d501.js\,\PostList\\n)/script>script>self.__next_f.push(1,14:\$\,\$L1e\,null,{\post\:{\metadata\:{\title\:\Next.js Environment Variables: The Missing Guide\,\publishedAt\:\2025-12-23\,\image\:\/images/posts/nextjs-env-variables/main.png\,\summary\:\Next.js environment variables fail silently - unless you force them to fail early. You can think of it as a loaded gun on the wall: it may sit there quietly for weeks, until one day it goes off in production.\,\tags\:\nextjs\,\env\,\typescript\,\security\,\react\,\zod\},\readTime\:6,\slug\:\nextjs-environment-variables\,\content\:null,\snippet\:false,\imageSize\:{\height\:544,\width\:897,\type\:\png\},\image\:{\imageSize\:\$14:0:props:post:imageSize\,\placeholder\:\data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAACXBIWXMAAAsTAAALEwEAmpwYAAAALUlEQVR4nAEiAN3/ADo5sv9oVNT+tn///0EXs+QAAABX/1A6qf7U+f//m6f/5D1wFExBXchjAAAAAElFTkSuQmCC\},\toc\:{\level\:2,\title\:\Solution\,\id\:\solution\},{\level\:2,\title\:\Types\,\id\:\types\},{\level\:2,\title\:\Runtime check\,\id\:\runtime-check\},{\level\:2,\title\:\Security Scan\,\id\:\security-scan\},{\level\:2,\title\:\Conclusion\,\id\:\conclusion\},{\level\:2,\title\:\Useful Links\,\id\:\useful-links\}}},\$\,\$L1f\,null,{\posts\:{\metadata\:{\title\:\Perfect Is the Enemy of Done - The Story of ratu.dev\,\publishedAt\:\2025-08-22\,\image\:\/images/posts/story-of-ratu-dev/main.png\,\summary\:\After 10 years on the web and dozens of projects, it still took me 3 years to build my own digital home - ratu.dev. Its basically a monument to my procrastination, and to idealism\,\tags\:\personal\},\readTime\:3,\slug\:\story-of-ratu-dev\,\content\:null,\snippet\:false,\imageSize\:{\height\:1231,\width\:1848,\type\:\png\},\image\:{\imageSize\:\$14:1:props:posts:0:imageSize\,\placeholder\:\data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAPklEQVR4nAEzAMz/AAEYIf4bNTv+5P///rzWy/4AhJWX/3GSkv9pkYz/aYVt/wAkKCztAAoC7ihEM+6SoX7tv/kaqamydw4AAAAASUVORK5CYII\},\toc\:{\level\:2,\title\:\Inspiration list\,\id\:\inspiration-list\},{\level\:2,\title\:\Summary\,\id\:\summary\}},{\metadata\:{\title\:\Mastering Node.js scripting: Tools/CLI/AI/Steroids\,\publishedAt\:\2025-08-30\,\image\:\/images/posts/scripting/main.png\,\summary\:\Scripting isnt about perfection — its about saving time. It should be pragmatic, fast, and never something you get stuck on. Over the past 10 years, I went from barely seeing the point of scripting to writing quick scripts in minutes — scripts that save time, and that time stack up over the years.\,\tags\:\nodejs\,\javascript\,\typescript\,\scripts\,\automation\,\disableToc\:\true\},\readTime\:26,\slug\:\mastering-nodejs-scripting\,\content\:null,\snippet\:false,\imageSize\:{\height\:1141,\width\:1667,\type\:\png\},\image\:{\imageSize\:\$14:1:props:posts:1:imageSize\,\placeholder\:\data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAN0lEQVR4nGNQEFT8U1hU8ze2ov2vlqr5H4Z5rQ3//kNBU3zmf4bFAQw3Og3Mr/cIW193Y2C4BgC8BRrHiIIHPQAAAABJRU5ErkJggg\},\toc\:{\level\:2,\title\:\Essentials\,\id\:\essentials\},{\level\:2,\title\:\Node.js APIs\,\id\:\nodejs-apis\},{\level\:2,\title\:\File System Access `fs`\,\id\:\file-system-access-fs\},{\level\:2,\title\:\Process: Arguments and Exit Codes\,\id\:\process-arguments-and-exit-codes\},{\level\:2,\title\:\Paths in Node.js\,\id\:\paths-in-nodejs\},{\level\:2,\title\:\CLI\,\id\:\cli\},{\level\:2,\title\:\Node.js scripts on steroids - zx\,\id\:\nodejs-scripts-on-steroids-zx\},{\level\:2,\title\:\AI Scripting Toolkit\,\id\:\ai-scripting-toolkit\},{\level\:2,\title\:\Example scripts - Practice\,\id\:\example-scripts-practice\},{\level\:2,\title\:\Distribution of Scripts\,\id\:\distribution-of-scripts\},{\level\:2,\title\:\Summary and Conclusion\,\id\:\summary-and-conclusion\}},{\metadata\:{\title\:\Node.js Scripting Cheatsheet (Battle Tested)\,\publishedAt\:\2025-08-20\,\summary\:\This cheatsheet is a collection of battle-tested Node.js snippets I use for scripting, automation, and everyday backend hacks. Copy, paste, and adapt — no fluff, just code that works.\,\image\:\/images/snippets/nodejs-cheatsheet/main.png\,\tags\:\nodejs\,\cheatsheet\,\automation\,\scripts\,\type\:\cheatsheet\,\github\:\https://github.com/ra2dev/nodejs-cheat-sheet/tree/main\},\readTime\:17,\slug\:\nodejs-cheatsheet\,\content\:null,\snippet\:true,\imageSize\:{\height\:347,\width\:896,\type\:\png\},\image\:{\imageSize\:\$14:1:props:posts:2:imageSize\,\placeholder\:\data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAK0lEQVR4nGNgYGBgeXTooOD/7//FGBgYGBmWLFnC29g4k/v+8ePci+NjWQDTkQ0Bf+8SGgAAAABJRU5ErkJggg\},\toc\:{\level\:2,\title\:\File-System Essentials (icon: Folder)\,\id\:\file-system-essentials-icon-folder\},{\level\:2,\title\:\CLI Parameters \u0026 Environment (icon: Terminal)\,\id\:\cli-parameters-and-environment-icon-terminal\},{\level\:2,\title\:\Process \u0026 Child Processes (icon: GitFork)\,\id\:\process-and-child-processes-icon-gitfork\},{\level\:2,\title\:\HTTP Client Requests (icon: Globe)\,\id\:\http-client-requests-icon-globe\},{\level\:2,\title\:\TypeScript in Node (icon: FileCode2)\,\id\:\typescript-in-node-icon-filecode2\},{\level\:2,\title\:\Automation \u0026 Scheduling (icon: Clock)\,\id\:\automation-and-scheduling-icon-clock\},{\level\:2,\title\:\Logging, Debugging, Safety Nets (icon: Bug)\,\id\:\logging-debugging-safety-nets-icon-bug\},{\level\:2,\title\:\Packaging \u0026 Distribution (icon: Package)\,\id\:\packaging-and-distribution-icon-package\},{\level\:2,\title\:\Streams \u0026 Buffers (icon: Waves)\,\id\:\streams-and-buffers-icon-waves\},{\level\:2,\title\:\Event Loop \u0026 Async Patterns (icon: RefreshCcw)\,\id\:\event-loop-and-async-patterns-icon-refreshccw\},{\level\:2,\title\:\Testing \u0026 Coverage (icon: FlaskConical)\,\id\:\testing-and-coverage-icon-flaskconical\},{\level\:2,\title\:\Live Reload \u0026 Watchers (icon: RefreshCw)\,\id\:\live-reload-and-watchers-icon-refreshcw\},{\level\:2,\title\:\Concurrency (icon: Cpu)\,\id\:\concurrency-icon-cpu\},{\level\:2,\title\:\Security \u0026 HTTPS Basics (icon: Lock)\,\id\:\security-and-https-basics-icon-lock\},{\level\:2,\title\:\CLI / UX Enhancements (icon: Command)\,\id\:\cli-ux-enhancements-icon-command\},{\level\:2,\title\:\Node Runtime Flags \u0026 Profiling (icon: Flag)\,\id\:\node-runtime-flags-and-profiling-icon-flag\},{\level\:2,\title\:\Containerization \u0026 Serverless Deploy (icon: Server)\,\id\:\containerization-and-serverless-deploy-icon-server\},{\level\:2,\title\:\Boot \u0026 Run Basics (icon: PlayCircle)\,\id\:\boot-and-run-basics-icon-playcircle\},{\level\:2,\title\:\CJS to MJS (icon: UnfoldVertical)\,\id\:\cjs-to-mjs-icon-unfoldvertical\}},{\metadata\:{\title\:\Save to Google Sheets with Nodejs/Nextjs\,\publishedAt\:\2025-08-20\,\summary\:\Learn how to use Google Sheets as a simple backend for your Node.js/Next.js app with minimal setup. Perfect for quick prototypes and easy data management.\,\image\:\/images/snippets/gsheet/main.png\,\tags\:\nodejs\,\gsheet\,\nextjs\,\crud\},\readTime\:3,\slug\:\google-sheets-data-saving-nodejs-nextjs-snippet\,\content\:null,\snippet\:true,\imageSize\:{\height\:347,\width\:896,\type\:\png\},\image\:{\imageSize\:\$14:1:props:posts:3:imageSize\,\placeholder\:\data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAKklEQVR4nGNISkri+/37v9Cl05dU2NkYJBgaGho4UtRSWWxtIzh9fHwEAOU5Cz4c7cyvAAAAAElFTkSuQmCC\},\toc\:{\level\:2,\title\:\Installation\,\id\:\installation\},{\level\:2,\title\:\Full Code\,\id\:\full-code\},{\level\:2,\title\:\CRUD\,\id\:\crud\},{\level\:2,\title\:\Nextjs Version\,\id\:\nextjs-version\},{\level\:2,\title\:\Summary\,\id\:\summary\}},{\metadata\:{\title\:\Simple password protection for a Next.js app\,\publishedAt\:\2025-08-20\,\summary\:\Secure pages in a Next.js app with password protection with middleware and WWW-Authenticate: no user database or external auth service, no UI required.\,\image\:\/images/snippets/password-protection/main.png\,\canonical\:\https://blog.ratu.dev/simple-password-protection-for-a-next-js-app-1ff21ada93a3\,\tags\:\auth\,\nextjs\,\web\,\javascript\,\typescript\},\readTime\:3,\slug\:\simple-password-protection-for-a-next-js-app\,\content\:null,\snippet\:true,\imageSize\:{\height\:360,\width\:896,\type\:\png\},\image\:{\imageSize\:\$14:1:props:posts:4:imageSize\,\placeholder\:\data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJUlEQVR4nGNgYGDgYGBgYH7//r3cncuXtRigAgzZ2dmS2dnZqgCJ5QhrI/k7+wAAAABJRU5ErkJggg\},\toc\:{\level\:2,\title\:\Password Protection Components\,\id\:\password-protection-components\},{\level\:2,\title\:\Full Code\,\id\:\full-code\},{\level\:2,\title\:\Summary\,\id\:\summary\}}},\$L20\\n)/script>script>self.__next_f.push(1,21:I6489,\440\,\static/chunks/440-a720412ecf546db4.js\,\713\,\static/chunks/713-a98e84a52def2dba.js\,\144\,\static/chunks/144-22d3e9edf8340076.js\,\944\,\static/chunks/944-a7fcd457c1336867.js\,\908\,\static/chunks/908-64a17f68de53ce6d.js\,\524\,\static/chunks/524-c4a13ce6e586703d.js\,\183\,\static/chunks/183-206a2249f9a2c3ad.js\,\588\,\static/chunks/588-d881c5c2c5e86f7b.js\,\974\,\static/chunks/app/page-d7607bcac0e5d501.js\,\SubscribeBlock\\n20:\$\,\$L21\,null,{\waitFor\:\animation-1\,\duration\:1.4,\path\:{\type\:\bottom\,\height\:180},{\type\:\bottom-right-corner\},{\type\:\right\,\width\:40},\className\:\md:ml-10px\}\n)/script>/body>/html>
Subdomains
Date
Domain
IP
admini.ratu.dev
2025-10-08
104.26.11.183
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]