[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Fusing-redis-for-caching":671,"blog-author-\u002Fblog\u002Fusing-redis-for-caching":1830,"i-material-symbols:arrow-back-rounded":1845},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Manage account","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","XlSALC7vYCXHcmcXnjJViwIZKsqnQWF4bn4o9RrcSBE",{"id":87,"extension":5,"links":88,"meta":668,"stem":669,"__hash__":670},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300,303,307,311,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,461,465,469,473,477,481,485,488,491,494,497,501,505,508,512,516,520,524,528,532,536,540,544,548,552,556,559,563,567,571,575,579,582,585,588,592,595,599,603,607,611,614,618,622,625,628,631,635,639,643,646,649,652,656,660,664],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.linuxFlatpak","Linux Flatpak installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fflatpak",{"key":209,"label":210,"href":211},"downloads.guides.linuxSnap","Linux Snap installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fsnap",{"key":213,"label":214,"href":215},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":217,"label":218,"href":219},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":221,"label":222,"href":223},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":225,"label":226,"href":227},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":229,"label":230,"href":231},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":233,"label":234,"href":235},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":237,"label":238,"href":239},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":241,"label":242,"href":243},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":245,"label":246,"href":247},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":249,"label":250,"href":251},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":253,"label":254,"href":255},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":257,"label":258,"href":259},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":261,"label":262,"href":263},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":265,"label":266,"href":267},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":269,"label":270,"href":271},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":273,"label":274,"href":275},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":277,"label":278,"href":279},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":281,"label":282,"href":283},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":285,"label":286,"href":287},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":289,"label":290,"href":291},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":293,"label":294,"href":295},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":297,"label":298,"href":299},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":301,"label":302,"href":92},"docs.desktop.download","Desktop download docs",{"key":304,"label":305,"href":306},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":308,"label":309,"href":310},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":312,"label":313,"href":215},"docs.piecesOS.install","PiecesOS install docs",{"key":315,"label":316,"href":317},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":319,"label":320,"href":321},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":323,"label":324,"href":325},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":327,"label":328,"href":329},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":331,"label":332,"href":333},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":335,"label":336,"href":337},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":343,"label":344,"href":345},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":347,"label":348,"href":349},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":351,"label":352,"href":353},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":355,"label":356,"href":357},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":359,"label":360,"href":361},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":363,"label":364,"href":365},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":367,"label":368,"href":369},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":371,"label":372,"href":373},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":375,"label":376,"href":377},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":379,"label":380,"href":381},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":383,"label":384,"href":385},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":387,"label":388,"href":389},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":391,"label":392,"href":393},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":395,"label":396,"href":397},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":399,"label":400,"href":401},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":403,"label":404,"href":405},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":407,"label":408,"href":409},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":411,"label":412,"href":413},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":415,"label":416,"href":417},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":419,"label":420,"href":421},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":423,"label":424,"href":425},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":427,"label":428,"href":429},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":431,"label":432,"href":433},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":435,"label":436,"href":437},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":439,"label":440,"href":441},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":443,"label":444,"href":445},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":447,"label":448,"href":449},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":451,"label":452,"href":453},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":455,"label":456,"href":457},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":459,"label":58,"href":460},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":462,"label":463,"href":464},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":466,"label":467,"href":468},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":470,"label":471,"href":472},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":474,"label":475,"href":476},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":478,"label":479,"href":480},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":482,"label":483,"href":484},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":486,"label":34,"href":487},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":489,"label":43,"href":490},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":492,"label":46,"href":493},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":495,"label":496,"href":493},"social.twitter","Twitter",{"key":498,"label":499,"href":500},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":502,"label":503,"href":504},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":506,"label":49,"href":507},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":509,"label":510,"href":511},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":513,"label":514,"href":515},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":517,"label":518,"href":519},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":521,"label":522,"href":523},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":525,"label":526,"href":527},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":529,"label":530,"href":531},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":533,"label":534,"href":535},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":537,"label":538,"href":539},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":541,"label":542,"href":543},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":545,"label":546,"href":547},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":549,"label":550,"href":551},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":553,"label":554,"href":555},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":557,"label":558,"href":255},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":560,"label":561,"href":562},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":564,"label":565,"href":566},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":568,"label":569,"href":570},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":572,"label":573,"href":574},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":576,"label":577,"href":578},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":580,"label":581,"href":66},"legal.privacyPolicy","Privacy policy",{"key":583,"label":584,"href":69},"legal.refundPolicy","Refund policy",{"key":586,"label":587,"href":72},"legal.terms","Terms",{"key":589,"label":590,"href":591},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":593,"label":594,"href":511},"videos.youtubeChannel","YouTube channel",{"key":596,"label":597,"href":598},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":600,"label":601,"href":602},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":604,"label":605,"href":606},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":608,"label":609,"href":610},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":612,"label":613,"href":527},"sales.feedback","Feedback discussions",{"key":615,"label":616,"href":617},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":619,"label":620,"href":621},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":623,"label":624,"href":19},"routes.home","Home route",{"key":626,"label":627,"href":56},"routes.about","About route",{"key":629,"label":630,"href":12},"routes.downloads","Downloads route",{"key":632,"label":633,"href":634},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":636,"label":637,"href":638},"routes.pricing","Pricing route","\u002Fpricing",{"key":640,"label":641,"href":642},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":644,"label":645,"href":22},"routes.enterprise","Enterprise route",{"key":647,"label":648,"href":62},"routes.contact","Contact route",{"key":650,"label":651,"href":59},"routes.updates","Updates route",{"key":653,"label":654,"href":655},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":657,"label":658,"href":659},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":661,"label":662,"href":663},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":665,"label":666,"href":667},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","2AvfSWI6bZACH5Kr1ZS3txMLjteRjCjbDR_ul1uRZ9Q",{"id":672,"title":673,"author":674,"authorPhoto":675,"authorPhotoAlt":676,"authorSlug":677,"body":678,"buttonText":1817,"buttonUrl":1817,"category":1818,"date":1819,"description":1820,"draft":1821,"editorsPick":1821,"extension":1822,"featured":1821,"image":1823,"imageAlt":1824,"meta":1825,"navigation":32,"ogImage":1817,"ogImageAlt":1817,"path":1826,"seo":1827,"stem":1828,"tags":1817,"__hash__":1829},"blog\u002Fblog\u002Fusing-redis-for-caching.md","Using Redis Caching and the Redis CLI to Improve API Performance","Aseem Wangoo","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fauthor.jpeg","Aseem Wangoo.","aseem-wangoo",{"type":679,"value":680,"toc":1789},"minimark",[681,686,703,714,729,732,736,751,758,765,785,799,802,808,814,817,846,850,865,869,883,887,896,899,905,911,914,923,929,935,943,948,954,961,972,979,985,991,1017,1029,1033,1036,1042,1048,1058,1065,1071,1078,1084,1087,1093,1099,1106,1112,1118,1128,1134,1140,1151,1155,1161,1168,1174,1180,1187,1218,1227,1230,1236,1242,1246,1253,1259,1265,1275,1278,1282,1289,1295,1301,1304,1307,1311,1317,1322,1325,1330,1336,1342,1357,1363,1369,1372,1378,1381,1387,1393,1396,1402,1406,1409,1412,1415,1419,1422,1436,1442,1448,1451,1454,1458,1464,1475,1485,1502,1508,1514,1518,1525,1530,1536,1539,1545,1551,1558,1565,1572,1591,1605,1608,1614,1617,1621,1628,1631,1637,1643,1650,1654,1664,1669,1675,1678,1686,1689,1694,1701,1707,1713,1724,1734,1739,1746,1749,1755,1761,1767,1771],[682,683,685],"h2",{"id":684},"what-is-redis","What is Redis?",[687,688,689,690,694,695,698,699,702],"p",{},"Using Redis caching is a simple way to improve the performance of your APIs. Redis (",[691,692,693],"strong",{},"Re","mote ",[691,696,697],{},"Di","ctionary ",[691,700,701],{},"S","erver) is a fast, open-source, in-memory, key-value data store. It delivers sub-millisecond response times, enabling millions of requests per second for real-time applications.",[687,704,705,706,713],{},"Redis is a key-value-based ",[707,708,712],"a",{"href":709,"rel":710},"https:\u002F\u002Fdatabasecamp.de\u002Fen\u002Fdata\u002Fnosql-databases",[711],"nofollow","NoSQL"," database that stores data in memory (in RAM).",[687,715,716,717,722,723,728],{},"Redis is often used for caching; geospatial storage; chat, messaging, and queues; and gaming leaderboards. It’s well-suited to these tasks because it is simple, fast, and easy-to-use; supports a variety ",[707,718,721],{"href":719,"rel":720},"https:\u002F\u002Fredis.io\u002Fdocs\u002Fdata-types\u002Ftutorial\u002F",[711],"of data structures","; allows for storing key and value pairs as large as 512MB; and ",[707,724,727],{"href":725,"rel":726},"https:\u002F\u002Fredis.io\u002Ftopics\u002Fsentinel",[711],"Redis Sentinel"," provides high availability for non-clustered Redis.",[687,730,731],{},"However, Redis requires huge amounts of RAM, depending on the type of application you’re running; failovers in master components cause all slave components to lose all of their data; and data can only be accessed via keys.",[682,733,735],{"id":734},"setting-up-redis","Setting up Redis",[687,737,738,739,744,745,750],{},"We will set up ",[707,740,743],{"href":741,"rel":742},"https:\u002F\u002Fredis.io\u002Fdownload\u002F",[711],"Redis"," using ",[707,746,749],{"href":747,"rel":748},"https:\u002F\u002Fhub.docker.com\u002F_\u002Fredis\u002F",[711],"Docker",".",[687,752,753],{},[754,755],"img",{"alt":756,"src":757},"CLI command to install Redis.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-001.png",[687,759,760],{},[707,761,764],{"href":762,"rel":763},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=4a2548ad24",[711],"Save this code",[687,766,767,768,773,774,778,779,784],{},"Nowadays, there are some hosting providers, such as ",[707,769,772],{"href":770,"rel":771},"https:\u002F\u002Faws.amazon.com\u002Fredis\u002F",[711],"AWS",", ",[707,775,743],{"href":776,"rel":777},"https:\u002F\u002Fredis.com\u002F",[711],", or ",[707,780,783],{"href":781,"rel":782},"https:\u002F\u002Fupstash.com\u002F?utm_source=goredis",[711],"Upstash",", that provide Redis on the cloud.",[687,786,787,788,792,793,798],{},"There are many ways to connect to ",[707,789,743],{"href":790,"rel":791},"https:\u002F\u002Fredis.io\u002Fdocs\u002Fclients\u002F",[711],". In our case, we will be using the ",[707,794,797],{"href":795,"rel":796},"https:\u002F\u002Fredis.io\u002Ftopics\u002Frediscli",[711],"Redis CLI",". Since we have the Docker setup ready, let's connect.",[687,800,801],{},"Here is an example of using Redis CLI commands to set, get and delete a value from the Redis database:",[687,803,804],{},[754,805],{"alt":806,"src":807},"The Redis CLI commands to set, get and delete.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-002.png",[687,809,810],{},[707,811,764],{"href":812,"rel":813},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=a41d49b693",[711],[687,815,816],{},"Some other useful Redis CLI commands:",[818,819,820,828,834,840],"ul",{},[821,822,823,827],"li",{},[824,825,826],"code",{},"keys",": find all keys",[821,829,830,833],{},[824,831,832],{},"FLUSHALL",": delete all keys from all databases",[821,835,836,839],{},[824,837,838],{},"FLUSHDB",": delete all keys from the currently selected database",[821,841,842,845],{},[824,843,844],{},"EXPIRE key 120",": delete a key in 120 seconds",[682,847,849],{"id":848},"caching-apis-with-go-and-redis","Caching APIs with Go and Redis",[687,851,852,853,858,859,864],{},"There are multiple clients available in ",[707,854,857],{"href":855,"rel":856},"https:\u002F\u002Fredis.io\u002Fdocs\u002Fclients\u002F#go",[711],"Go"," for implementing Redis. However, in this article, we will be using ",[707,860,863],{"href":861,"rel":862},"https:\u002F\u002Fgithub.com\u002Fgo-redis\u002Fredis",[711],"go-redis",". Let’s look into how this works with Redis caching.",[866,867,868],"h3",{"id":863},"Go-Redis",[687,870,871,872,773,877,882],{},"Go-Redis is a type-safe Go Redis client library. It’s a Redis client that is able to support a Redis cluster and is designed to store and update slot info automatically with a cluster change. It also supports features like ",[707,873,876],{"href":874,"rel":875},"https:\u002F\u002Fredis.uptrace.dev\u002Fguide\u002Fgo-redis-pubsub.html",[711],"Pub\u002FSub",[707,878,881],{"href":879,"rel":880},"https:\u002F\u002Fredis.uptrace.dev\u002Fguide\u002Fgo-redis-sentinel.html",[711],"Sentinel",", and pipelining.",[866,884,886],{"id":885},"create-apis-using-gorilla-mux","Create APIs using Gorilla Mux",[687,888,889,890,895],{},"We will be using ",[707,891,894],{"href":892,"rel":893},"https:\u002F\u002Fgithub.com\u002Fgorilla\u002Fmux",[711],"Gorilla Mux"," to create the APIs locally. Gorilla Mux implements a request router and dispatcher to match the incoming requests.",[687,897,898],{},"Install it using the following command:",[687,900,901],{},[754,902],{"alt":903,"src":904},"CLI command to install Gorilla Mux.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-003.png",[687,906,907],{},[707,908,764],{"href":909,"rel":910},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=e07c4f912d",[711],[687,912,913],{},"We will register the following endpoints:",[915,916,917],"ol",{},[821,918,919,922],{},[824,920,921],{},"GET \u002Fusers\u002F:id","— to get a user’s information based on their id. A response might look like this:",[687,924,925],{},[754,926],{"alt":927,"src":928},"Sample response to the command ","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-004.png",[687,930,931],{},[707,932,764],{"href":933,"rel":934},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=c0134fae43",[711],[915,936,937],{},[821,938,939,942],{},[824,940,941],{},"GET \u002Fusers"," — returns the users present in the database. A response might look like this:",[687,944,945],{},[754,946],{"alt":927,"src":947},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-005.png",[687,949,950],{},[707,951,764],{"href":952,"rel":953},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=aec94ab5ab",[711],[687,955,956,957,960],{},"Next, we create the router instance using the ",[824,958,959],{},"mux.NewRouter()"," and assign the above-created routes to the respective handlers.",[687,962,963,964,967,968,971],{},"Each of the corresponding handlers is passed ",[824,965,966],{},"ResponseWriter"," and ",[824,969,970],{},"Request"," as parameters, which help in returning the desired response to the client.",[687,973,974,975,978],{},"We then specify the server details using ",[824,976,977],{},"http.Server"," to run an HTTP server.",[687,980,981],{},[754,982],{"alt":983,"src":984},"Code snippet to run an HTTP server when using Redis caching.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-006.png",[687,986,987],{},[707,988,764],{"href":989,"rel":990},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=c70946acf7",[711],[818,992,993,999,1005,1011],{},[821,994,995,998],{},[824,996,997],{},"Handler",": This is the object that responds to the incoming HTTP requests that we created above.",[821,1000,1001,1004],{},[824,1002,1003],{},"Addr",": This specifies the TCP address for the server to listen on. By default, this is 80.",[821,1006,1007,1010],{},[824,1008,1009],{},"WriteTimeout",": The maximum duration before timing out the writes of the response.",[821,1012,1013,1016],{},[824,1014,1015],{},"ReadTimeout",": The maximum duration for reading the entire incoming request.",[687,1018,1019,1020,1023,1024,1026,1027,750],{},"Finally, we run the server using ",[824,1021,1022],{},"ListenAndServe"," which listens to the network address specified in the ",[824,1025,1003],{}," and serves the requests based on the ",[824,1028,997],{},[866,1030,1032],{"id":1031},"setting-up-postgres","Setting up Postgres",[687,1034,1035],{},"We will be using Postgres for our database. Install it using Docker by running the following:",[687,1037,1038],{},[754,1039],{"alt":1040,"src":1041},"CLI command to install Postgres.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-007.png",[687,1043,1044],{},[707,1045,764],{"href":1046,"rel":1047},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=dca6489bc8",[711],[687,1049,1050,1051,1054,1055,750],{},"Then, verify that the new container is created and running ",[824,1052,1053],{},"docker ps -a"," at ",[824,1056,1057],{},"0.0.0.0:5432",[687,1059,1060,1061,1064],{},"To the database from your browser, install",[824,1062,1063],{},"pgAdmin"," and connect to it using the above credentials. If all is well, you should see this:",[687,1066,1067],{},[754,1068],{"alt":1069,"src":1070},"Example of a successful login.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-008.png",[687,1072,1073,1074,1077],{},"We will create a table called ",[824,1075,1076],{},"users"," which will have the following schema:",[687,1079,1080],{},[754,1081],{"alt":1082,"src":1083},"Example user schema.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-009.png",[687,1085,1086],{},"Let’s insert some dummy data using the following:",[687,1088,1089],{},[754,1090],{"alt":1091,"src":1092},"Code snippet to install dummy data into your user schema.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-010.png",[687,1094,1095],{},[707,1096,764],{"href":1097,"rel":1098},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=3146479130",[711],[687,1100,1101,1102,1105],{},"To connect to ",[824,1103,1104],{},"Postgres"," with Go, we’ll install this:",[687,1107,1108],{},[754,1109],{"alt":1110,"src":1111},"CLI commands to connect to Postgres with Go.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-011.png",[687,1113,1114],{},[707,1115,764],{"href":1116,"rel":1117},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=0e4a41837f",[711],[687,1119,1120,1121,1124,1125,1127],{},"Here is the ",[824,1122,1123],{},"struct"," for the ",[824,1126,1076],{},":",[687,1129,1130],{},[754,1131],{"alt":1132,"src":1133},"Code snippet to illustrate the Users struct.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-012.png",[687,1135,1136],{},[707,1137,764],{"href":1138,"rel":1139},"https:\u002F\u002Fb6278012-e3a5-4917-aedd-d98df2ddcf25.pieces.cloud\u002F?p=067e45b616",[711],[687,1141,1142,1143,1146,1147,1150],{},"Once the ",[824,1144,1145],{},"get users"," API and the ",[824,1148,1149],{},"get users by id"," API are created, we will use Gorilla Mux to create a localhost server and listen to the endpoints.",[682,1152,1154],{"id":1153},"redis-caching-for-apis","Redis Caching for APIs",[687,1156,1157],{},[754,1158],{"alt":1159,"src":1160},"Redis between database and client.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-013.png",[687,1162,1163,1164,1167],{},"To connect to Redis, we create a Redis Client using",[824,1165,1166],{},"NewClient",". We specify the address at which the Redis exists like so:",[687,1169,1170],{},[754,1171],{"alt":1172,"src":1173},"Code snippet that shows how we specify an address for Redis.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-014.png",[687,1175,1176],{},[707,1177,764],{"href":1178,"rel":1179},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=a39141bff8",[711],[687,1181,1182,1183,1186],{},"The configuration options are available through the ",[824,1184,1185],{},"redis.Options"," parameter.",[818,1188,1189,1201,1207,1213],{},[821,1190,1191,1193,1194,1197,1198,750],{},[824,1192,1003],{},": The string of the host and the port address. Since we are hosting Redis locally, the value is ",[824,1195,1196],{},"127.0.0.1",". By default, Redis runs on port ",[824,1199,1200],{},"6379",[821,1202,1203,1206],{},[824,1204,1205],{},"DB",": The database which will be selected after connecting to the server. By choosing 0, we will use the default database.",[821,1208,1209,1212],{},[824,1210,1211],{},"DialTimeout",": This specifies the timeout for establishing a new connection if our connection to the Redis server breaks.",[821,1214,1215,1217],{},[824,1216,1015],{},": This allows us to put a timeout for the socket reads. If any of the Redis server requests reach this timeout, the command calling it will fail instead of blocking the server.",[687,1219,1220,1221,1226],{},"To check if we connected to the server, we call ",[707,1222,1225],{"href":1223,"rel":1224},"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fgo-redis\u002Fredis\u002Fv8#Client.Ping",[711],"Ping"," using the client we created above. If there is no error, we are connected to the Redis server.",[687,1228,1229],{},"Finally, we return the Redis client, which internally may have zero or more connections.",[687,1231,1232],{},[754,1233],{"alt":1234,"src":1235},"A code snippet to return the Redis client.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-015.png",[687,1237,1238],{},[707,1239,764],{"href":1240,"rel":1241},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=b9a74bbc84",[711],[866,1243,1245],{"id":1244},"get-and-set-keys","Get and Set Keys",[687,1247,1248,1249,1252],{},"Whenever the front end asks for the details of a particular user, we fetch that user from the API and then cache it. Subsequent requests for the particular user will be served from the cache until the cache key expires (we set this expiration to 20 seconds). We will be making use of",[824,1250,1251],{},"Set"," to set the value in the cache.",[687,1254,1255],{},[754,1256],{"alt":1257,"src":1258},"Code snippet showing the use of the Set command.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-016.png",[687,1260,1261],{},[707,1262,764],{"href":1263,"rel":1264},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=57064ab312",[711],[687,1266,1267,1270,1271,1274],{},[691,1268,1269],{},"Note",": Here we take the ",[824,1272,1273],{},"user struct"," as input. We then convert the Go struct into JSON (i.e., marshaling), as JSON is a language-independent data format.",[687,1276,1277],{},"We set the key pair with an optional expiration parameter of 20 seconds. This means the key will automatically expire in 20 seconds. If there is no expiration parameter, the key will not expire.",[866,1279,1281],{"id":1280},"get-keys","Get Keys",[687,1283,1284,1285,1288],{},"We will be making use of",[824,1286,1287],{},"Get"," to retrieve the value of a key:",[687,1290,1291],{},[754,1292],{"alt":1293,"src":1294},"Code snippet to illustrate the Get command.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-017.png",[687,1296,1297],{},[707,1298,764],{"href":1299,"rel":1300},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=8b0646b7f4",[711],[687,1302,1303],{},"The response is in the form of a string. We convert this byte data into the original user struct (i.e., unmarshalling).",[687,1305,1306],{},"Inside this function, we add a Redis publisher (which we’ll discuss in the next section).",[866,1308,1310],{"id":1309},"calling-apis-with-redis-caching","Calling APIs with Redis Caching",[687,1312,1313,1314,1316],{},"We have this API endpoint hosted locally—",[824,1315,921],{}," — to get a user’s information based on the id. Once the client calls this endpoint, we first check if the value for this request can be served from the cache.",[687,1318,1319,1321],{},[691,1320,1269],{},": If the data exists inside the cache, we set the source to \"cache.\"",[687,1323,1324],{},"Logically, the first request will always hit the server, so the time to get the response will be longer.",[687,1326,1327,1329],{},[691,1328,1269],{},": When getting the value from the server, we set the source to\"API.\"",[687,1331,1332],{},[754,1333],{"alt":1334,"src":1335},"Code snippet that demonstrates Redis caching.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-018.png",[687,1337,1338],{},[707,1339,764],{"href":1340,"rel":1341},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=483b46a627",[711],[687,1343,1344,1345,1348,1349,1352,1353,1356],{},"As we can see in the above snippet, we first invoke ",[824,1346,1347],{},"redis.GetUser"," to check the cache. This function checks for the id inside the cache; if the id is present, it returns the value. If the result fails, the function returns ",[824,1350,1351],{},"null"," and we proceed to invoke the API ",[824,1354,1355],{},"GetUserByID",", which hits our Postgres database.",[687,1358,1359],{},[754,1360],{"alt":1361,"src":1362},"Code snippet that shows the results of a request to the an API that uses Redis caching.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-019.png",[687,1364,1365],{},[707,1366,764],{"href":1367,"rel":1368},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=2cac4fab16",[711],[687,1370,1371],{},"This is how it looks when the key is not present in Redis:",[687,1373,1374],{},[754,1375],{"alt":1376,"src":1377},"Example of a non-present key.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-020.png",[687,1379,1380],{},"The result from the API uses Redis caching, so the subsequent requests are now served by the cache (for 20 seconds, until the key expires).",[687,1382,1383],{},[754,1384],{"alt":1385,"src":1386},"An example of a cached response being quickly returned.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-021.png",[687,1388,1389],{},[707,1390,764],{"href":1391,"rel":1392},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=9a624dab00",[711],[687,1394,1395],{},"This is how it looks when the key is present in Redis:",[687,1397,1398],{},[754,1399],{"alt":1400,"src":1401},"An example of when the key is properly cached.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-022.png",[682,1403,1405],{"id":1404},"redis-subscription-using-pubsub","Redis Subscription using Pub\u002FSub",[687,1407,1408],{},"In the field of software engineering, publish-subscribe is a pattern where senders (publishers) categorize the messages into channels without knowing if there are any subscribers.",[687,1410,1411],{},"On the other hand, subscribers show interest in one or more channels and only receive messages that are of interest without knowing if there are any publishers.",[687,1413,1414],{},"This decoupling of publishers and subscribers allows for greater scalability.",[866,1416,1418],{"id":1417},"redis-pubsub","Redis Pub\u002FSub",[687,1420,1421],{},"We will be using Redis for pub\u002Fsub, however, there are various alternatives including Apache Kafka and Google cloud Pub\u002FSub.",[687,1423,1424,1425,967,1428,1431,1432,1435],{},"In order to subscribe to channels, for example, ",[824,1426,1427],{},"foo",[824,1429,1430],{},"bar",", the client uses",[824,1433,1434],{},"SUBSCRIBE"," and provides the names of the channels:",[687,1437,1438],{},[754,1439],{"alt":1440,"src":1441},"CLI command to subscribe to example channels.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-023.png",[687,1443,1444],{},[707,1445,764],{"href":1446,"rel":1447},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=2ee443b3a1",[711],[687,1449,1450],{},"Messages sent by other clients to these channels will be pushed by Redis to all of the subscribed clients.",[687,1452,1453],{},"Once we have a Redis client subscribed to a channel, that client can no longer execute any other operations besides unsubscribing from the current channel and subscribing to more channels.",[866,1455,1457],{"id":1456},"go-redis-publisher","Go-Redis Publisher",[687,1459,1460,1463],{},[824,1461,1462],{},"Go-redis"," allows users to publish messages and subscribe to channels. It also automatically re-connects to the Redis Server when there is a network error.",[687,1465,1466,1467,1470,1471,1474],{},"Inside our ",[824,1468,1469],{},"get user"," function, we will create a publisher using",[824,1472,1473],{},"redis.Publish()",". This function takes two arguments: the name of the channel to which we want to send the message and the message.",[687,1476,1477,1478,1481,1482,1484],{},"In our case, we set the channel name to ",[824,1479,1480],{},"send-user-name"," and the payload is the response from ",[824,1483,1347],{}," (see above).",[687,1486,1487,1488,1491,1492,1495,1496,1499,1500,750],{},"We are sending the marshaled payload to the channel using ",[824,1489,1490],{},"Publish"," because it allows us to transfer the data as ",[824,1493,1494],{},"[]byte",". Since we are using a ",[824,1497,1498],{},"User"," struct, it can be encoded into a ",[824,1501,1494],{},[687,1503,1504],{},[754,1505],{"alt":1506,"src":1507},"Example of a pub\u002Fsub payload and the publication.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-024.png",[687,1509,1510],{},[707,1511,764],{"href":1512,"rel":1513},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=41bd4ab4c7",[711],[866,1515,1517],{"id":1516},"go-redis-subscriber","Go-Redis Subscriber",[687,1519,1520,1521,1524],{},"We create a subscriber using the",[824,1522,1523],{},"redis.Subscribe()"," function.",[687,1526,1527,1528,750],{},"We will have one argument: the channel we want to subscribe to. In our case, this is ",[824,1529,1480],{},[687,1531,1532,1535],{},[824,1533,1534],{},"Subscribe"," subscribes the client to the specified channels. Since this method does not wait for a response from Redis, the subscription may not be active immediately.",[687,1537,1538],{},"We create a new file that connects to the same Redis instance and calls the following:",[687,1540,1541],{},[754,1542],{"alt":1543,"src":1544},"Code snippet that connects to Redis and requests data.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-025.png",[687,1546,1547],{},[707,1548,764],{"href":1549,"rel":1550},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=20544980a4",[711],[687,1552,1553,1554,1557],{},"The result of the ",[824,1555,1556],{},"subscribe"," is a Pub\u002FSub, and we extract the channel property out of this object.",[687,1559,1560,1561,1564],{},"This ",[824,1562,1563],{},"Channel"," returns a Go channel for concurrently receiving messages. If the channel is full for 30 seconds, then the message is dropped.",[687,1566,1567,1568,1571],{},"We loop over the channel and extract the data from it, which is of the type ",[824,1569,1570],{},"Message",". Each message object comprises three arguments:",[915,1573,1574,1579,1585],{},[821,1575,1576,1578],{},[824,1577,1563],{},": The channel name",[821,1580,1581,1584],{},[824,1582,1583],{},"Payload",": The marshaled data received in the channel",[821,1586,1587,1590],{},[824,1588,1589],{},"Pattern",": The pattern for the message",[687,1592,1593,1594,1597,1598,1601,1602,1604],{},"The data received inside the message can be fetched using ",[824,1595,1596],{},"msg.Payload",". Since it is marshaled, we will unmarshal it using ",[824,1599,1600],{},"UnmarshalBinary"," and transform it back into a ",[824,1603,1498],{}," struct.",[687,1606,1607],{},"Finally, we can access the struct properties and print inside the console. We can also print the message’s channel name just for fun!",[687,1609,1610],{},[754,1611],{"alt":1612,"src":1613},"Example of a printed message.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-026.png",[687,1615,1616],{},"Here, we get the message, “Received message from send-user-name” and the user details for Bob.",[682,1618,1620],{"id":1619},"calling-apis-using-react","Calling APIs using React",[687,1622,1623,1624,1627],{},"In the above section, we created and hosted APIs locally using ",[707,1625,894],{"href":892,"rel":1626},[711],". We will now consume these APIs from the front end using React.",[687,1629,1630],{},"We’ll be using Axios to call the APIs for which we previously discussed Redis caching. Let’s install this dependency by running the following command:",[687,1632,1633],{},[754,1634],{"alt":1635,"src":1636},"CLI command to install Axios.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-027.png",[687,1638,1639],{},[707,1640,764],{"href":1641,"rel":1642},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=c60c4dba0a",[711],[687,1644,1645,1646,1649],{},"Axios is a lightweight HTTP client which makes calling requests very intuitive. It is similar to the JavaScript Fetch API. It works well with JSON data and does the heavy lifting of setting the request headers. Axios handles errors well when accessing the response and integrates well with ",[824,1647,1648],{},"async-await"," syntax, plus it can be used on the server as well as the client.",[866,1651,1653],{"id":1652},"integrate-with-react","Integrate with React",[687,1655,1656,1657,967,1660,1663],{},"We will be using the hooks ",[824,1658,1659],{},"useEffect",[824,1661,1662],{},"useState",". A React hook is a special function that lets you “hook into” React features.",[866,1665,1667],{"id":1666},"useeffect",[824,1668,1659],{},[687,1670,1671,1672,1674],{},"Using this hook, we can inform React that our components need to do something after rendering. By default, ",[824,1673,1659],{}," runs after each render of the component where it’s called. A common use of this hook is to fetch and display data.",[687,1676,1677],{},"React remembers the function you passed and invokes it after the DOM updates.",[687,1679,1680,1682,1683,1685],{},[691,1681,1269],{},": We have an empty array at the end of the ",[824,1684,1659],{}," hook to make sure that the internal function inside renders only once.",[687,1687,1688],{},"If we want our effects to run less often, we provide the second argument (which is an array of values). These can be considered the dependencies for the effect, and if there are any changes since the last time the effect was run, the effect runs again.",[866,1690,1692],{"id":1691},"usestate",[824,1693,1662],{},[687,1695,1696,1697,1700],{},"This is a way of adding a state to components and preserving some values between function calls. In general, variables “disappear” when the function exits, but state variables are preserved by React. This state can be an array, object, number, boolean, etc. The argument passed to ",[824,1698,1699],{},"useState()"," is the initial state.",[687,1702,1703],{},[754,1704],{"alt":1705,"src":1706},"An example of useState.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-028.png",[687,1708,1709],{},[707,1710,764],{"href":1711,"rel":1712},"https:\u002F\u002Faseem.pieces.cloud\u002F?p=61fa45af76",[711],[687,1714,1715,1716,1719,1720,1723],{},"To make a ",[824,1717,1718],{},"GET"," request using Axios, we use the ",[824,1721,1722],{},".get()"," method. The response is returned as an object.",[687,1725,1726,1727,1730,1731,750],{},"We use the ",[824,1728,1729],{},".data"," property from the response to get the requested data and set it inside the hook using ",[824,1732,1733],{},"setFetchedData",[1735,1736,1738],"h4",{"id":1737},"request-responses","Request Responses",[687,1740,1741,1742,1745],{},"When the page loads for the first time, the API hits our backend. The resulting ",[824,1743,1744],{},"fetchedData"," is then displayed on the page.",[687,1747,1748],{},"Notice that the source is the API.",[687,1750,1751],{},[754,1752],{"alt":1753,"src":1754},"Request response from the API.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-029.png",[687,1756,1757,1758],{},"On the next request, the API hits our cache, displayed with ",[824,1759,1760],{},"source: cache",[687,1762,1763],{},[754,1764],{"alt":1765,"src":1766},"Response from the API that's using Redis caching.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fimg-030.png",[682,1768,1770],{"id":1769},"conclusion","Conclusion",[687,1772,1773,1774,1777,1778,1783,1784,750],{},"In this article, we used a ",[824,1775,1776],{},"postgres"," database to store users’ data. We created endpoints using Gorilla Mux, and on top of those endpoints, we integrated Redis caching into the API response from a React application. Remember that Redis is a powerful tool and what we covered is just the tip of the iceberg. For more information, consider reading the docs at ",[707,1779,1782],{"href":1780,"rel":1781},"http:\u002F\u002Fredis.io\u002F",[711],"redis.io",". You can also follow along with this article by watching this ",[707,1785,1788],{"href":1786,"rel":1787},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=pgh4DicuixA&t=1s",[711],"YouTube tutorial",{"title":1790,"searchDepth":1791,"depth":1791,"links":1792},"",2,[1793,1794,1795,1801,1806,1811,1816],{"id":684,"depth":1791,"text":685},{"id":734,"depth":1791,"text":735},{"id":848,"depth":1791,"text":849,"children":1796},[1797,1799,1800],{"id":863,"depth":1798,"text":868},3,{"id":885,"depth":1798,"text":886},{"id":1031,"depth":1798,"text":1032},{"id":1153,"depth":1791,"text":1154,"children":1802},[1803,1804,1805],{"id":1244,"depth":1798,"text":1245},{"id":1280,"depth":1798,"text":1281},{"id":1309,"depth":1798,"text":1310},{"id":1404,"depth":1791,"text":1405,"children":1807},[1808,1809,1810],{"id":1417,"depth":1798,"text":1418},{"id":1456,"depth":1798,"text":1457},{"id":1516,"depth":1798,"text":1517},{"id":1619,"depth":1791,"text":1620,"children":1812},[1813,1814,1815],{"id":1652,"depth":1798,"text":1653},{"id":1666,"depth":1798,"text":1659},{"id":1691,"depth":1798,"text":1662},{"id":1769,"depth":1791,"text":1770},null,"Software Development","2022-09-22T00:00:00.000Z","Let's learn how to use Redis caching and the redis CLI! Redis is simple, fast, and easy-to-use, and supports a variety of data structures.",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-redis-for-caching\u002Fhero.jpeg","Using Redis for Caching.",{},"\u002Fblog\u002Fusing-redis-for-caching",{"title":673,"description":1820},"blog\u002Fusing-redis-for-caching","6Z4ih3iE1c-_f-AARjGLY_z2VxJNugQsNilbiWN5cP4",{"id":1831,"title":674,"body":1832,"description":1836,"draft":1821,"extension":1822,"meta":1839,"navigation":32,"path":1840,"photo":1841,"photoAlt":1817,"seo":1842,"stem":1843,"__hash__":1844},"authors\u002Fauthors\u002Faseem-wangoo.md",{"type":679,"value":1833,"toc":1837},[1834],[687,1835,1836],{},"Aseem is a seasoned software engineer with over 10 years of expertise and leadership experience. Who combines technical proficiency with strategic insight to deliver impactful solutions and guide teams toward success.",{"title":1790,"searchDepth":1791,"depth":1791,"links":1838},[],{},"\u002Fauthors\u002Faseem-wangoo","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fplaceholder.svg",{"title":674,"description":1836},"authors\u002Faseem-wangoo","BykQHOcgQJBv43HQCbia0i-Yq_w6EXmHMny9Py5gycQ",{"left":1846,"top":1846,"width":1847,"height":1847,"rotate":1846,"vFlip":1821,"hFlip":1821,"body":1848},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]