CINXE.COM
Schema Language – AuthZed Docs
<!DOCTYPE html><html><head><meta charSet="utf-8"/><title>Schema Language – AuthZed Docs</title><meta name="robots" content="index,follow"/><meta name="description" content="Welcome to the SpiceDB and AuthZed docs site."/><meta property="og:title" content="Schema Language"/><meta property="og:description" content="Welcome to the SpiceDB and AuthZed docs site."/><meta property="og:url" content="https://authzed.com/docs/spicedb/concepts/schema"/><link rel="canonical" href="https://authzed.com/docs/spicedb/concepts/schema"/><meta name="theme-color" content="#111" media="(prefers-color-scheme: dark)"/><meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/><style> :root { --nextra-primary-hue: 290deg; --nextra-primary-saturation: 100%; --nextra-navbar-height: 4rem; --nextra-menu-height: 3.75rem; --nextra-banner-height: 2.5rem; } .dark { --nextra-primary-hue: 45deg; --nextra-primary-saturation: 100%; } </style><script defer="" data-domain="authzed.com" data-api="/api/event" src="/js/script.js"></script><meta name="next-head-count" content="12"/><link rel="preload" href="https://docs-authzed.vercel.app/docs/_next/static/media/a34f9d1faa5f3315-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="https://docs-authzed.vercel.app/docs/_next/static/css/42cac7439c63aa1d.css" as="style"/><link rel="stylesheet" href="https://docs-authzed.vercel.app/docs/_next/static/css/42cac7439c63aa1d.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="https://docs-authzed.vercel.app/docs/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/webpack-03b2a85b9553dc59.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/framework-25c5f1bd495ca617.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/main-62f008f3cc49f011.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/pages/_app-ae40aa9fc402f797.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/9845-593929ea3f75fb39.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/6920-f20f16aa679ecf38.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/chunks/pages/spicedb/concepts/schema-3f8b67126c0ed285.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/_qU6EoFbs5qnijdzF7DDY/_buildManifest.js" defer=""></script><script src="https://docs-authzed.vercel.app/docs/_next/static/_qU6EoFbs5qnijdzF7DDY/_ssgManifest.js" defer=""></script><style id="__jsx-e653edd9ed17fee7">svg.jsx-e653edd9ed17fee7{-webkit-mask-image:-webkit-linear-gradient(30deg,black 25%,rgba(0,0,0,.2)50%,black 75%);mask-image:-webkit-linear-gradient(30deg,black 25%,rgba(0,0,0,.2)50%,black 75%);mask-image:-moz-linear-gradient(30deg,black 25%,rgba(0,0,0,.2)50%,black 75%);mask-image:-o-linear-gradient(30deg,black 25%,rgba(0,0,0,.2)50%,black 75%);mask-image:linear-gradient(60deg,black 25%,rgba(0,0,0,.2)50%,black 75%);-webkit-mask-size:400%;mask-size:400%;-webkit-mask-position:0%;mask-position:0%}svg.jsx-e653edd9ed17fee7:hover{-webkit-mask-position:100%;mask-position:100%;-webkit-transition:mask-position 1s ease,-webkit-mask-position 1s ease;-moz-transition:mask-position 1s ease,-webkit-mask-position 1s ease;-o-transition:mask-position 1s ease,-webkit-mask-position 1s ease;transition:mask-position 1s ease,-webkit-mask-position 1s ease}</style></head><body><div id="__next"><div class="__className_3b04d1"><!--$--><!--/$--><script>!function(){try{var d=document.documentElement,c=d.classList;c.remove('light','dark');var e=localStorage.getItem('theme');if('system'===e||(!e&&true)){var t='(prefers-color-scheme: dark)',m=window.matchMedia(t);if(m.media!==t||m.matches){d.style.colorScheme = 'dark';c.add('dark')}else{d.style.colorScheme = 'light';c.add('light')}}else if(e){c.add(e|| '')}if(e==='light'||e==='dark')d.style.colorScheme=e}catch(e){}}()</script><div dir="ltr"><script>document.documentElement.setAttribute('dir','ltr')</script><script>try{if(localStorage.getItem("nextra-banner")==='0'){document.body.classList.add('nextra-banner-hidden')}}catch(e){}</script><div class="nextra-banner-container nx-sticky nx-top-0 nx-z-20 nx-flex nx-items-center md:nx-relative nx-h-[var(--nextra-banner-height)] [body.nextra-banner-hidden_&]:nx-hidden nx-text-slate-50 dark:nx-text-white nx-bg-neutral-900 dark:nx-bg-[linear-gradient(1deg,#383838,#212121)] nx-px-2 ltr:nx-pl-10 rtl:nx-pr-10 print:nx-hidden"><div class="nx-w-full nx-truncate nx-px-4 nx-text-center nx-font-medium nx-text-sm"><a href="https://github.com/authzed/spicedb">SpiceDB is 100% open source. Please help us by starring our GitHub repo. ↗</a></div></div><div class="nextra-nav-container nx-sticky nx-top-0 nx-z-20 nx-w-full nx-bg-transparent print:nx-hidden"><div class="nextra-nav-container-blur nx-pointer-events-none nx-absolute nx-z-[-1] nx-h-full nx-w-full nx-bg-white dark:nx-bg-dark nx-shadow-[0_2px_4px_rgba(0,0,0,.02),0_1px_0_rgba(0,0,0,.06)] dark:nx-shadow-[0_-1px_0_rgba(255,255,255,.1)_inset] contrast-more:nx-shadow-[0_0_0_1px_#000] contrast-more:dark:nx-shadow-[0_0_0_1px_#fff]"></div><nav class="nx-mx-auto nx-flex nx-h-[var(--nextra-navbar-height)] nx-max-w-[90rem] nx-items-center nx-justify-end nx-gap-2 nx-pl-[max(env(safe-area-inset-left),1.5rem)] nx-pr-[max(env(safe-area-inset-right),1.5rem)]"><a class="nx-flex nx-items-center hover:nx-opacity-75 ltr:nx-mr-auto rtl:nx-ml-auto" href="https://authzed.com"><svg height="30" viewBox="0 0 473 129" fill="none" xmlns="http://www.w3.org/2000/svg" class="jsx-e653edd9ed17fee7"><path d="M156.323 67.2372C155.771 77.5631 152.673 87.8613 147.397 96.7616C138.56 111.672 123.755 123.318 104.936 126.849C95.5409 128.536 88.7081 128.322 81.0342 127.145C75.4984 125.912 72.0133 121.415 75.7302 116.07C80.2848 109.518 86.7402 105.213 93.1836 100.907C111.978 88.3476 131.942 77.8497 152.09 67.6769C154.343 66.5412 156.481 64.2944 156.323 67.2372Z" fill="#A13974" class="jsx-e653edd9ed17fee7"></path><path d="M169.694 43.1434C174.427 39.3991 179 34.589 182.239 29.4357L182.244 29.4319L182.249 29.428C185.814 23.753 183.79 18.6293 177.26 17.0761C169.752 15.2893 163.386 16.0089 155.702 17.0761C153.83 17.3361 153.354 17.7392 152.713 18.1434C151.417 18.962 151.274 21.461 153.14 21.7721C156.557 21.9856 167.747 21.2212 170.43 22.4124C178.076 25.8071 157.153 37.1094 154.403 39.2974C152.754 40.6079 151.963 40.4505 151.036 38.3872C143.759 22.2096 131.909 10.7385 115.35 4.22533C104.971 0.144998 94.2793 -0.789116 83.2332 0.606922C77.2806 1.35893 72.6108 2.99382 67.1419 5.12434C65.3384 5.82691 62.9525 7.0237 61.2933 7.97718C57.4042 10.2078 53.8247 12.7097 50.5669 15.4969C47.7294 17.9245 49.396 22.2704 53.1141 22.6195L121.571 29.0465C124.609 29.3316 126.11 32.88 124.2 35.2587L86.0185 84.0794C84.6298 85.8084 86.403 88.6596 88.462 87.8355C103.995 81.6016 119.096 74.0364 134.047 66.5187C146.515 60.2493 158.778 51.7777 169.694 43.1434Z" fill="#FB5B62" class="jsx-e653edd9ed17fee7"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M98.5791 47.3169C101.016 44.706 98.8693 40.4751 95.323 40.8998L33.3125 48.3264C31.4368 48.551 29.876 49.9028 29.4974 51.7535C27.1126 63.4103 28.064 75.1499 32.5509 86.9003C34.2311 91.3023 34.3364 91.4291 29.8007 91.9868C29.2093 92.0594 28.6167 92.1398 28.0231 92.2202C24.6035 92.6838 21.1517 93.1517 17.7111 92.175C9.39414 89.8058 22.1859 81.9275 23.1518 78.5611C23.865 76.0752 20.4861 75.1441 18.3735 76.6361C11.604 81.4168 5.15918 86.9958 1.16277 94.3733C0.308766 96.0814 0.414398 98.2165 0.735706 99.3713C3.10202 107.874 21.4225 106.33 27.4584 105.246C35.3675 103.826 41.0781 103.311 48.7624 100.963C50.8581 100.322 50.8969 100.109 54.0987 96.8099C70.321 81.752 85.1666 61.2215 98.5791 47.3169Z" fill="#EFA16D" class="jsx-e653edd9ed17fee7"></path><path d="M215.477 93.194C222.603 93.194 228.849 89.8311 231.731 84.5466V92.3933H236.455V50.1168H231.731V58.0437C228.849 52.7591 222.603 49.3162 215.477 49.3162C203.867 49.3162 194.579 58.444 194.579 71.3352C194.579 84.0661 203.867 93.194 215.477 93.194ZM199.783 71.3352C199.783 61.4066 206.669 54.2004 216.037 54.2004C224.605 54.2004 231.811 60.2056 231.811 71.3352C231.811 82.3847 224.605 88.3098 216.037 88.3098C206.669 88.3098 199.783 81.1837 199.783 71.3352Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path><path d="M277.91 75.6589V50.1168H272.786V75.4987C272.786 83.8259 269.023 88.3098 261.976 88.3098C255.01 88.3098 251.167 83.8259 251.167 75.4987V50.1168H246.043V75.6589C246.043 86.7084 251.968 93.194 261.976 93.194C272.065 93.194 277.91 86.7084 277.91 75.6589Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path><path d="M289.298 92.3933H294.423V54.921H299.947V50.1168H294.423V36.0247L289.298 38.1865V50.1168H284.094V54.921H289.298V92.3933Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path><path d="M306.5 92.3933H311.624V67.0114C311.624 58.6842 315.388 54.2004 322.514 54.2004C329.48 54.2004 333.243 58.6842 333.243 67.0114V92.3933H338.367V66.7712C338.367 55.7217 332.843 49.3162 323.475 49.3162C317.95 49.3162 313.866 51.5581 311.544 55.4014C311.624 53.2395 311.624 51.0777 311.624 48.6756V30.7401H306.5V92.3933Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path><path d="M343.819 92.3933H377.608L379.21 81.0235H362.315L378.969 51.5581V49.9567H346.621L345.02 61.3265H360.473L343.819 90.7919V92.3933Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path><path d="M403.992 93.4342C412.399 93.4342 419.125 89.9112 423.849 83.6658L415.682 76.8599C412.56 80.7833 408.716 82.705 404.232 82.705C398.627 82.705 394.544 79.6623 393.343 74.618H423.849C425.611 56.8426 414.962 48.9158 403.352 48.9158C391.021 48.9158 381.413 57.9636 381.413 71.3352C381.413 84.3063 390.46 93.4342 403.992 93.4342ZM393.503 65.8905C394.864 61.8069 398.467 59.1647 403.271 59.1647C407.996 59.1647 411.198 61.5667 412.159 65.8905H393.503Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path><path d="M448.96 93.194C453.684 93.194 458.328 91.5926 461.21 88.55L461.29 92.3933H472.5V30.4999H459.849V42.5904C459.849 46.1134 459.929 49.4763 460.089 52.7591C457.127 50.3571 453.123 49.156 448.96 49.156C437.51 49.156 427.821 58.1238 427.821 71.175C427.821 84.2263 437.51 93.194 448.96 93.194ZM440.472 71.175C440.472 64.7695 444.796 60.686 450.641 60.686C456.406 60.686 460.65 64.7695 460.65 71.175C460.65 77.5805 456.406 81.6641 450.641 81.6641C444.796 81.6641 440.472 77.5805 440.472 71.175Z" fill="currentColor" class="jsx-e653edd9ed17fee7"></path></svg></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-font-medium nx-subpixel-antialiased" aria-current="true" href="/docs/spicedb/getting-started/discovering-spicedb"><span class="nx-absolute nx-inset-x-0 nx-text-center">SpiceDB Documentation</span><span class="nx-invisible nx-font-medium">SpiceDB Documentation</span></a><a class="nx-text-sm contrast-more:nx-text-gray-700 contrast-more:dark:nx-text-gray-100 nx-relative -nx-ml-2 nx-hidden nx-whitespace-nowrap nx-p-2 md:nx-inline-block nx-text-gray-600 hover:nx-text-gray-800 dark:nx-text-gray-400 dark:hover:nx-text-gray-200" aria-current="false" href="/docs/authzed/guides/picking-a-product"><span class="nx-absolute nx-inset-x-0 nx-text-center">AuthZed Product Documentation</span><span class="nx-invisible nx-font-medium">AuthZed Product Documentation</span></a><div class="nextra-search nx-relative md:nx-w-64"><div class="nx-relative nx-flex nx-items-center nx-text-gray-900 contrast-more:nx-text-gray-800 dark:nx-text-gray-300 contrast-more:dark:nx-text-gray-300"><input spellcheck="false" class="nx-block nx-w-full nx-appearance-none nx-rounded-lg nx-px-3 nx-py-2 nx-transition-colors nx-text-base nx-leading-tight md:nx-text-sm nx-bg-black/[.05] dark:nx-bg-gray-50/10 focus:nx-bg-white dark:focus:nx-bg-dark placeholder:nx-text-gray-500 dark:placeholder:nx-text-gray-400 contrast-more:nx-border contrast-more:nx-border-current" type="search" placeholder="Search Documentation..." value=""/></div></div><a href="https://github.com/authzed/spicedb" target="_blank" rel="noreferrer" class="nx-p-2 nx-text-current"><svg width="24" height="24" fill="currentColor" viewBox="3 3 18 18"><title>GitHub</title><path d="M12 3C7.0275 3 3 7.12937 3 12.2276C3 16.3109 5.57625 19.7597 9.15374 20.9824C9.60374 21.0631 9.77249 20.7863 9.77249 20.5441C9.77249 20.3249 9.76125 19.5982 9.76125 18.8254C7.5 19.2522 6.915 18.2602 6.735 17.7412C6.63375 17.4759 6.19499 16.6569 5.8125 16.4378C5.4975 16.2647 5.0475 15.838 5.80124 15.8264C6.51 15.8149 7.01625 16.4954 7.18499 16.7723C7.99499 18.1679 9.28875 17.7758 9.80625 17.5335C9.885 16.9337 10.1212 16.53 10.38 16.2993C8.3775 16.0687 6.285 15.2728 6.285 11.7432C6.285 10.7397 6.63375 9.9092 7.20749 9.26326C7.1175 9.03257 6.8025 8.08674 7.2975 6.81794C7.2975 6.81794 8.05125 6.57571 9.77249 7.76377C10.4925 7.55615 11.2575 7.45234 12.0225 7.45234C12.7875 7.45234 13.5525 7.55615 14.2725 7.76377C15.9937 6.56418 16.7475 6.81794 16.7475 6.81794C17.2424 8.08674 16.9275 9.03257 16.8375 9.26326C17.4113 9.9092 17.76 10.7281 17.76 11.7432C17.76 15.2843 15.6563 16.0687 13.6537 16.2993C13.98 16.5877 14.2613 17.1414 14.2613 18.0065C14.2613 19.2407 14.25 20.2326 14.25 20.5441C14.25 20.7863 14.4188 21.0746 14.8688 20.9824C16.6554 20.364 18.2079 19.1866 19.3078 17.6162C20.4077 16.0457 20.9995 14.1611 21 12.2276C21 7.12937 16.9725 3 12 3Z"></path></svg><span class="nx-sr-only">GitHub</span><span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a><a href="https://discord.gg/spicedb" target="_blank" rel="noreferrer" class="nx-p-2 nx-text-current"><svg width="24" height="24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 5 30.67 23.25"><title>Discord</title><path d="M26.0015 6.9529C24.0021 6.03845 21.8787 5.37198 19.6623 5C19.3833 5.48048 19.0733 6.13144 18.8563 6.64292C16.4989 6.30193 14.1585 6.30193 11.8336 6.64292C11.6166 6.13144 11.2911 5.48048 11.0276 5C8.79575 5.37198 6.67235 6.03845 4.6869 6.9529C0.672601 12.8736 -0.41235 18.6548 0.130124 24.3585C2.79599 26.2959 5.36889 27.4739 7.89682 28.2489C8.51679 27.4119 9.07477 26.5129 9.55525 25.5675C8.64079 25.2265 7.77283 24.808 6.93587 24.312C7.15286 24.1571 7.36986 23.9866 7.57135 23.8161C12.6241 26.1255 18.0969 26.1255 23.0876 23.8161C23.3046 23.9866 23.5061 24.1571 23.7231 24.312C22.8861 24.808 22.0182 25.2265 21.1037 25.5675C21.5842 26.5129 22.1422 27.4119 22.7621 28.2489C25.2885 27.4739 27.8769 26.2959 30.5288 24.3585C31.1952 17.7559 29.4733 12.0212 26.0015 6.9529ZM10.2527 20.8402C8.73376 20.8402 7.49382 19.4608 7.49382 17.7714C7.49382 16.082 8.70276 14.7025 10.2527 14.7025C11.7871 14.7025 13.0425 16.082 13.0115 17.7714C13.0115 19.4608 11.7871 20.8402 10.2527 20.8402ZM20.4373 20.8402C18.9183 20.8402 17.6768 19.4608 17.6768 17.7714C17.6768 16.082 18.8873 14.7025 20.4373 14.7025C21.9717 14.7025 23.2271 16.082 23.1961 17.7714C23.1961 19.4608 21.9872 20.8402 20.4373 20.8402Z"></path></svg><span class="nx-sr-only">Discord</span><span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a><button type="button" aria-label="Menu" class="nextra-hamburger -nx-mr-2 nx-rounded nx-p-2 active:nx-bg-gray-400/20 md:nx-hidden"><svg fill="none" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor" class=""><g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16"></path></g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16"></path><g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 18h16"></path></g></svg></button></nav></div><div class="nx-mx-auto nx-flex nx-max-w-[90rem]"><div class="motion-reduce:nx-transition-none [transition:background-color_1.5s_ease] nx-bg-transparent"></div><aside class="nextra-sidebar-container nx-flex nx-flex-col md:nx-top-16 md:nx-shrink-0 motion-reduce:nx-transform-none nx-transform-gpu nx-transition-all nx-ease-in-out print:nx-hidden md:nx-w-64 md:nx-sticky md:nx-self-start max-md:[transform:translate3d(0,-100%,0)]"><div class="nx-px-4 nx-pt-4 md:nx-hidden"><div class="nextra-search nx-relative md:nx-w-64"><div class="nx-relative nx-flex nx-items-center nx-text-gray-900 contrast-more:nx-text-gray-800 dark:nx-text-gray-300 contrast-more:dark:nx-text-gray-300"><input spellcheck="false" class="nx-block nx-w-full nx-appearance-none nx-rounded-lg nx-px-3 nx-py-2 nx-transition-colors nx-text-base nx-leading-tight md:nx-text-sm nx-bg-black/[.05] dark:nx-bg-gray-50/10 focus:nx-bg-white dark:focus:nx-bg-dark placeholder:nx-text-gray-500 dark:placeholder:nx-text-gray-400 contrast-more:nx-border contrast-more:nx-border-current" type="search" placeholder="Search Documentation..." value=""/></div></div></div><div class="nx-overflow-y-auto nx-overflow-x-hidden nx-p-4 nx-grow md:nx-h-[calc(100vh-var(--nextra-navbar-height)-var(--nextra-menu-height))] nextra-scrollbar"><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100"><ul class="nx-flex nx-flex-col nx-gap-1 nextra-menu-desktop max-md:nx-hidden"><li class="open"><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Getting Started<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180 ltr:nx-rotate-90 rtl:nx-rotate-[-270deg]"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/discovering-spicedb">Discovering SpiceDB</a></li><li class=""><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Installing SpiceDB<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none" style="height:0"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-0 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/install/macos">macOS</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/install/docker">Docker</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/install/kubernetes">Kubernetes</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/install/debian">Ubuntu/Debian</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/install/rhel">RHEL/CentOS</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/install/windows">Windows</a></li></ul></div></div></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/installing-zed">Installing Zed</a></li><li class=""><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Coming From<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none" style="height:0"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-0 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/coming-from/opa">Open Policy Agent</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/coming-from/cancancan">Ruby on Rails</a></li></ul></div></div></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/protecting-a-blog">Protecting a Blog Application</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/client-libraries">Client Libraries</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/getting-started/faq">FAQ</a></li></ul></div></div></li><li class="open"><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Concepts<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180 ltr:nx-rotate-90 rtl:nx-rotate-[-270deg]"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/consistency">Consistency</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/commands">Commands</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/datastores">Datastores</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/datastore-migrations">Datastore Migrations</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/dispatch">Dispatch</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/relationships">Relationships</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/caveats">Relationship Caveats</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/reflection-apis">Reflection APIs</a></li><li class="nx-flex nx-flex-col nx-gap-1 active"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-bg-primary-100 nx-font-semibold nx-text-primary-800 dark:nx-bg-primary-400/10 dark:nx-text-primary-600 contrast-more:nx-border-primary-500 contrast-more:dark:nx-border-primary-500" href="/docs/spicedb/concepts/schema">Schema Language</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/operator">Operator</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/concepts/zanzibar">Zanzibar</a></li></ul></div></div></li><li class="open"><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Modeling & Integrating<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180 ltr:nx-rotate-90 rtl:nx-rotate-[-270deg]"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/developing-a-schema">Developing a Schema</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/representing-users">Representing Users</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/validation-testing-debugging">Validation, Testing, Debugging</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/recursion-and-max-depth">Recursion & Max Depth</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/protecting-a-list-endpoint">Protecting a List Endpoint</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/migrating-schema">Updating and Migrating Schema</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/access-control-management">Access Control Management</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/modeling/access-control-audit">Access Control Audit</a></li></ul></div></div></li><li class="open"><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Operations<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180 ltr:nx-rotate-90 rtl:nx-rotate-[-270deg]"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/ops/observability">Observability Tooling</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/ops/deploying-spicedb-operator">Deploying the SpiceDB Operator</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/ops/deploying-spicedb-on-eks">Deploying SpiceDB on AWS EKS</a></li><li class="nx-flex nx-flex-col nx-gap-1"><a class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50" href="/docs/spicedb/ops/load-testing">Load Testing</a></li></ul></div></div></li><li class="open"><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">API Reference<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180 ltr:nx-rotate-90 rtl:nx-rotate-[-270deg]"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://buf.build/authzed/api/docs/main:authzed.api.v1" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">gRPC API Reference<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://www.postman.com/authzed/workspace/spicedb/overview" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">HTTP API Reference<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li></ul></div></div></li><li class="open"><button class="nx-items-center nx-justify-between nx-gap-2 nx-text-left nx-w-full nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Links<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-h-[18px] nx-min-w-[18px] nx-rounded-sm nx-p-0.5 hover:nx-bg-gray-800/5 dark:hover:nx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="nx-origin-center nx-transition-transform rtl:-nx-rotate-180 ltr:nx-rotate-90 rtl:nx-rotate-[-270deg]"></path></svg></button><div class="nx-transform-gpu nx-overflow-hidden nx-transition-all nx-ease-in-out motion-reduce:nx-transition-none"><div class="nx-transition-opacity nx-duration-500 nx-ease-in-out motion-reduce:nx-transition-none nx-opacity-100 ltr:nx-pr-0 rtl:nx-pl-0 nx-pt-1"><ul class="nx-flex nx-flex-col nx-gap-1 nx-relative before:nx-absolute before:nx-inset-y-1 before:nx-w-px before:nx-bg-gray-200 before:nx-content-[""] dark:before:nx-bg-neutral-800 ltr:nx-pl-3 ltr:before:nx-left-0 rtl:nx-pr-3 rtl:before:nx-right-0 ltr:nx-ml-3 rtl:nx-mr-3"><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://discord.gg/spicedb" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">SpiceDB Discord<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://github.com/orgs/authzed/discussions/new?category=q-a" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">GitHub Discussions<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://github.com/authzed/awesome-spicedb#user-content-awesome-spicedb" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">SpiceDB Awesome List<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://github.com/authzed/examples" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Community Examples<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li><li class="nx-flex nx-flex-col nx-gap-1"><a href="https://authzed.com/zanzibar" target="_blank" rel="noreferrer" class="nx-flex nx-rounded nx-px-2 nx-py-1.5 nx-text-sm nx-transition-colors [word-break:break-word] nx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:nx-border nx-text-gray-500 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:nx-text-neutral-400 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50 contrast-more:nx-text-gray-900 contrast-more:dark:nx-text-gray-50 contrast-more:nx-border-transparent contrast-more:hover:nx-border-gray-900 contrast-more:dark:hover:nx-border-gray-50">Zanzibar Paper<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a></li></ul></div></div></li></ul></div></div></div><div class="nx-sticky nx-bottom-0 nx-bg-white dark:nx-bg-dark nx-mx-4 nx-py-4 nx-shadow-[0_-12px_16px_#fff] nx-flex nx-items-center nx-gap-2 dark:nx-border-neutral-800 dark:nx-shadow-[0_-12px_16px_#111] contrast-more:nx-border-neutral-400 contrast-more:nx-shadow-none contrast-more:dark:nx-shadow-none nx-border-t" data-toggle-animation="off"><div class="nx-grow nx-flex nx-flex-col"><button title="Change theme" class="nx-h-7 nx-rounded-md nx-px-2 nx-text-left nx-text-xs nx-font-medium nx-text-gray-600 nx-transition-colors dark:nx-text-gray-400 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50" id="headlessui-listbox-button-:R2njd6:" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state=""><div class="nx-flex nx-items-center nx-gap-2 nx-capitalize"><svg fill="none" viewBox="3 3 18 18" width="12" height="12" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="currentColor" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg><span class="">Light</span></div></button></div><button title="Hide sidebar" class="max-md:nx-hidden nx-h-7 nx-rounded-md nx-transition-colors nx-text-gray-600 dark:nx-text-gray-400 nx-px-2 hover:nx-bg-gray-100 hover:nx-text-gray-900 dark:hover:nx-bg-primary-100/5 dark:hover:nx-text-gray-50"><svg height="12" width="12" viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M4.177 7.823l2.396-2.396A.25.25 0 017 5.604v4.792a.25.25 0 01-.427.177L4.177 8.177a.25.25 0 010-.354z" class=""></path><path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm1.75-.25a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25H9.5v-13H1.75zm12.5 13H11v-13h3.25a.25.25 0 01.25.25v12.5a.25.25 0 01-.25.25z"></path></svg></button></div></aside><nav class="nextra-toc nx-order-last nx-hidden nx-w-64 nx-shrink-0 xl:nx-block print:nx-hidden nx-px-4" aria-label="table of contents"><div class="nextra-scrollbar nx-sticky nx-top-16 nx-overflow-y-auto nx-pr-4 nx-pt-6 nx-text-sm [hyphens:auto] nx-max-h-[calc(100vh-var(--nextra-navbar-height)-env(safe-area-inset-bottom))] ltr:-nx-mr-4 rtl:-nx-ml-4"><p class="nx-mb-4 nx-font-semibold nx-tracking-tight">On This Page</p><ul><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#definitions" class="nx-font-semibold nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Definitions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#object-type-definitions" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Object Type Definitions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#caveat-definitions" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Caveat Definitions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#relations" class="nx-font-semibold nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Relations</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#subject-relations" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Subject Relations</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#wildcards" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Wildcards</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#naming-relations" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Naming Relations</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#permissions" class="nx-font-semibold nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Permissions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#operations" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Operations</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#-union" class="ltr:nx-pl-8 rtl:nx-pr-8 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">+ (Union)</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#-intersection" class="ltr:nx-pl-8 rtl:nx-pr-8 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">& (Intersection)</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#--exclusion" class="ltr:nx-pl-8 rtl:nx-pr-8 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">- (Exclusion)</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#--arrow" class="ltr:nx-pl-8 rtl:nx-pr-8 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">-> (Arrow)</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#subject-relations-and-arrows" class="ltr:nx-pl-12 rtl:nx-pr-12 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Subject relations and Arrows</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#any-arrow" class="ltr:nx-pl-8 rtl:nx-pr-8 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">.any (Arrow)</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#all-intersection-arrow" class="ltr:nx-pl-8 rtl:nx-pr-8 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">.all (Intersection Arrow)</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#naming-permissions" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Naming Permissions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#comments" class="nx-font-semibold nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Comments</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#documentation-comments" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Documentation Comments</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#non-doc-comments" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Non-doc comments</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#full-example" class="nx-font-semibold nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Full Example</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#common-patterns" class="nx-font-semibold nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Common Patterns</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#group-membership" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Group membership</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#global-admin-permissions" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Global admin permissions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#synthetic-relations" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Synthetic relations</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#recursive-permissions" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Recursive permissions</a></li><li class="nx-my-2 nx-scroll-my-6 nx-scroll-py-6"><a href="#recursive-permissions-across-different-resource-types" class="ltr:nx-pl-4 rtl:nx-pr-4 nx-inline-block nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-300 contrast-more:nx-text-gray-900 contrast-more:nx-underline contrast-more:dark:nx-text-gray-50 nx-w-full nx-break-words">Recursive permissions across different resource types</a></li></ul><div class="nx-mt-8 nx-border-t nx-bg-white nx-pt-8 nx-shadow-[0_-12px_16px_white] dark:nx-bg-dark dark:nx-shadow-[0_-12px_16px_#111] nx-sticky nx-bottom-0 nx-flex nx-flex-col nx-items-start nx-gap-2 nx-pb-8 dark:nx-border-neutral-800 contrast-more:nx-border-t contrast-more:nx-border-neutral-400 contrast-more:nx-shadow-none contrast-more:dark:nx-border-neutral-400"><a href="https://github.com/authzed/docs/issues/new?title=Feedback%20for%20%E2%80%9CSchema%20Language%E2%80%9D&labels=feedback" target="_blank" rel="noreferrer" class="nx-text-xs nx-font-medium nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-100 contrast-more:nx-text-gray-800 contrast-more:dark:nx-text-gray-50"><span>Something unclear?<br/>Create an issue →</span><span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a><a class="nx-text-xs nx-font-medium nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-100 contrast-more:nx-text-gray-800 contrast-more:dark:nx-text-gray-50" href="https://github.com/authzed/docs/blob/main/pages/spicedb/concepts/schema.mdx">Edit this page</a><button aria-hidden="true" class="nx-flex nx-items-center nx-gap-1.5 nx-transition nx-opacity-0 nx-text-xs nx-font-medium nx-text-gray-500 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-100 contrast-more:nx-text-gray-800 contrast-more:dark:nx-text-gray-50">Scroll to top<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="-nx-rotate-90 nx-w-3.5 nx-h-3.5 nx-border nx-rounded-full nx-border-current"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg></button></div></div></nav><div id="reach-skip-nav"></div><article class="nx-w-full nx-break-words nextra-content nx-flex nx-min-h-[calc(100vh-var(--nextra-navbar-height))] nx-min-w-0 nx-justify-center nx-pb-8 nx-pr-[calc(env(safe-area-inset-right)-1.5rem)]"><main class="nx-w-full nx-min-w-0 nx-max-w-6xl nx-px-6 nx-pt-4 md:nx-px-12"><div class="nextra-breadcrumb nx-mt-1.5 nx-flex nx-items-center nx-gap-1 nx-overflow-hidden nx-text-sm nx-text-gray-500 dark:nx-text-gray-400 contrast-more:nx-text-current"><div class="nx-whitespace-nowrap nx-transition-colors nx-min-w-[24px] nx-overflow-hidden nx-text-ellipsis" title="SpiceDB Documentation">SpiceDB Documentation</div><svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-w-3.5 nx-shrink-0"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg><div class="nx-whitespace-nowrap nx-transition-colors nx-min-w-[24px] nx-overflow-hidden nx-text-ellipsis" title="Concepts">Concepts</div><svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-w-3.5 nx-shrink-0"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg><div class="nx-whitespace-nowrap nx-transition-colors nx-font-medium nx-text-gray-700 contrast-more:nx-font-bold contrast-more:nx-text-current dark:nx-text-gray-100 contrast-more:dark:nx-text-current" title="Schema Language">Schema Language</div></div><h1 class="nx-mt-2 nx-text-4xl nx-font-bold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100">Schema Language</h1> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">A SpiceDB schema defines the types of objects found, how those objects relate to one another, and the permissions that can be computed off of those relations.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The schema language's extension for use on a file system is <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">.zed</code>.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">You can experiment with schemas in real-time with the <a href="https://play.authzed.com" target="_blank" rel="noreferrer" class="nx-text-primary-600 nx-underline nx-decoration-from-font [text-underline-position:from-font]">Playground<span class="nx-sr-only nx-select-none"> (opens in a new tab)</span></a>.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The following video provides an overview of schema development using the Playground:</p> <br/> <div class=""><div id="" class=""></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">After studying this page's content, you may want to also read the <a class="nx-text-primary-600 nx-underline nx-decoration-from-font [text-underline-position:from-font]" href="/docs/spicedb/modeling/developing-a-schema">Developing a Schema</a> doc.</p> <h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">Definitions<a href="#definitions" id="definitions" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The top level of a Schema consists of zero or more <a class="nx-text-primary-600 nx-underline nx-decoration-from-font [text-underline-position:from-font]" href="/docs/spicedb/concepts/schema#object-type-definitions">Object Type definitions</a> and <a class="nx-text-primary-600 nx-underline nx-decoration-from-font [text-underline-position:from-font]" href="/docs/spicedb/concepts/caveats">Caveats</a>.</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * somecaveat is a caveat defined</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-keyword)">caveat</span><span style="color:var(--shiki-token-function)"> somecaveat</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-parameter)">someparameter</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-keyword)">int</span><span style="color:var(--shiki-color-text)">) {</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> someparameter </span><span style="color:var(--shiki-token-string-expression)">==</span><span style="color:var(--shiki-color-text)"> 42</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * someobjecttype is some type that I've decided to define</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">someobjecttype</span><span style="color:var(--shiki-color-text)"> {}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Note that the examples are unprefixed. You'll need to add the prefix from your permissions system if calling <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">WriteSchema</code> for a permissions system hosted in Serverless.</p></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Object Type Definitions<a href="#object-type-definitions" id="object-type-definitions" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">An Object Type definition is used to represent a new type of object. Objects are how SpiceDB represents instances of resources or subjects.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">It might help to think about Object Type definitions as similar to a class definition in an object-oriented programming language or a table definition in a SQL database.</p> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Caveat Definitions<a href="#caveat-definitions" id="caveat-definitions" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Caveats are a feature within SpiceDB that allows for relationships to be defined conditionally: the relationship will only be considered present if the caveat expression evaluates to true at query time.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">See the <a class="nx-text-primary-600 nx-underline nx-decoration-from-font [text-underline-position:from-font]" href="/docs/spicedb/concepts/caveats">Caveats documentation</a> to learn more.</p> <h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">Relations<a href="#relations" id="relations" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">A <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">relation</code> defines how two objects (or an object and subject) can relate to one another. For example, a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> on a document, or a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code> of a group.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Relations are always defined with a <em>name</em> and one (or more) allowed <em>types</em> of objects that can be the subjects of that relation:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * user represents a user</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * document represents a document in the system</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * reader relates a user that is a reader on the document</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">In the above example, the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">user</code> on <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> does not contain a sub-relation</p><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Occasionally you will see a subject which has a sub-relation such as <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">usergroup:admins#members</code> which refers not just to the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">usergroup</code> as a whole, but the set of members which have that relation to the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">usergroup</code>.</p></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Subject Relations<a href="#subject-relations" id="subject-relations" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Relations can also "contain" references to other relations/permissions.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, a group's <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code> relation might include the set of objects marked as <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code> of another group, indicating that the other group's members are, themselves, members of this group:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">group</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * member can include both users and *the set of members* of other specific groups.</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">member:</span><span style="color:var(--shiki-color-text)"> user </span><span style="color:var(--shiki-token-string-expression)">|</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">group#</span><span style="color:var(--shiki-color-text)">member</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Subject Relations are useful in RBAC-style permissions systems to grant "roles" to <em>sets</em> of subjects, such as the members of a team.</p></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Wildcards<a href="#wildcards" id="wildcards" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Relations can also specify wildcards to indicate that a grant can be made to the resource <em>type</em> as a whole, rather than a particular resource. This allows <em>public</em> access to be granted to a particular subject type.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">viewer</code> might indicate that <em>all</em> users can be granted the ability to view the resource:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">resource</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * viewer can be granted to a specific user or granted to *all* users.</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">viewer:</span><span style="color:var(--shiki-color-text)"> user </span><span style="color:var(--shiki-token-string-expression)">|</span><span style="color:var(--shiki-color-text)"> user:*</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">To be made public, the wildcard relationship would be written linking the specific document to <em>any</em> user:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="relationship" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="relationship" data-theme="default"><span class="line"><span style="color:var(--shiki-color-text)">resource:someresource viewer user:*</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Now <em>any</em> user is a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">viewer</code> of the resource.</p> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-yellow-100 nx-bg-yellow-50 nx-text-yellow-900 dark:nx-border-yellow-200/30 dark:nx-bg-yellow-700/30 dark:nx-text-yellow-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"">⚠️</div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Be <strong>very careful</strong> with wildcard support in your schema! <strong>Only</strong> grant it to read permissions, unless you intend to allow for universal writing.</p></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Naming Relations<a href="#naming-relations" id="naming-relations" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Relations define how one object relates to another object/subject, and thus <strong>relations should be named as nouns</strong>, read as <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">{relation name} (of the object)</code>.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Examples:</p> <table class="nx-block nx-overflow-x-scroll nextra-scrollbar nx-mt-6 nx-p-0 first:nx-mt-0"><thead><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600">Name</th><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600">Read as</th></tr></thead><tbody><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">reader of the document</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">writer</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">writer of the document</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">member of the group</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">parent of the folder</td></tr></tbody></table> <h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">Permissions<a href="#permissions" id="permissions" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">A <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">permission</code> defines a <em>computed set of subjects</em> that have a permission of some kind on the parent object. For example, is a user within the set of users that can <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">edit</code> a document.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Permissions are always defined with a <em>name</em> and an <em>expression</em> defining how that permission's allowed set of subjects is computed:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">writer:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * edit determines whether a user can edit the document</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> edit </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> writer</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * view determines whether a user can view the document</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> view </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">+</span><span style="color:var(--shiki-color-text)"> writer</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Operations<a href="#operations" id="operations" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Permissions support four kinds of operations: <strong>union</strong>, <strong>intersection</strong>, <strong>exclusion</strong> and <strong>arrow</strong>.</p> <h4 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-xl"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">+</code> (Union)<a href="#-union" id="-union" class="subheading-anchor" aria-label="Permalink for this section"></a></h4> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Unions together the relations/permissions referenced</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Union is the most common operation and is used to join different relations or permissions together to form a set of allowed subjects.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, to grant a permission to both the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code>s and <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">writer</code>s of a document:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-color-text)">permission combined </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">+</span><span style="color:var(--shiki-color-text)"> writer</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h4 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-xl"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">&</code> (Intersection)<a href="#-intersection" id="-intersection" class="subheading-anchor" aria-label="Permalink for this section"></a></h4> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Intersects the set of subjects found for the relations/permissions referenced</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Intersection allows for a permission to only include those subjects that were found in <strong>both</strong> relations/permissions.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, to grant a permission to a user that is both a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> and a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">writer</code> of a document:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-color-text)">permission read_and_write </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">&</span><span style="color:var(--shiki-color-text)"> writer</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h4 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-xl"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">-</code> (Exclusion)<a href="#--exclusion" id="--exclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h4> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Excludes the set of subjects found for the right side relation/permission from those found in the left side relation/permission</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Exclusion allows for computing the difference between two sets of relations/permissions</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, to grant a permission to a user that is <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> but not the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">writer</code> of a document:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-color-text)">permission can_only_read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">-</span><span style="color:var(--shiki-color-text)"> writer</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h4 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-xl"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">-></code> (Arrow)<a href="#--arrow" id="--arrow" class="subheading-anchor" aria-label="Permalink for this section"></a></h4> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Arrows allow for "walking" the heirarchy of relations (and permissions) defined for an <strong>object</strong> of a subject, referencing a permission or relation on the <em>resulting</em> subject's object.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, imagine a schema where a document is found under a folder:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">folder</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * parent_folder defines the folder that holds this document</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">parent_folder:</span><span style="color:var(--shiki-color-text)"> folder</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">We likely want to allow any <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> of the folder to <strong>also</strong> be a reader of the document.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">To accomplish this, we can use the arrow operator to walk to the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent_folder</code>'s <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">read</code> permission, thus including any subjects found there as well:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">folder</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">parent_folder:</span><span style="color:var(--shiki-color-text)"> folder</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * read defines whether a user can read the document</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> parent_folder</span><span style="color:var(--shiki-token-string-expression)">-></span><span style="color:var(--shiki-color-text)">read</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">The expression <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent_folder->read</code> indicates to "walk" from the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent_folder</code> of the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">document</code>, and then to include the subjects found for the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">read</code> permission of that folder.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Making use of a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">union</code>, we can also include the local <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> relation, allowing the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">read</code> permission on a document can check whether a user is a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> of a document or a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">reader</code> of its parent folder.</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">folder</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">parent_folder:</span><span style="color:var(--shiki-color-text)"> folder</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * read defines whether a user can read the document</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">+</span><span style="color:var(--shiki-color-text)"> parent_folder</span><span style="color:var(--shiki-token-string-expression)">-></span><span style="color:var(--shiki-color-text)">read</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">It is <em>recommended</em> that the right side of all arrows refer to <strong>permissions</strong>, instead of relations, as this allows for easy nested computation, and is more readable.</p></div></div> <h5 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-lg">Subject relations and Arrows<a href="#subject-relations-and-arrows" id="subject-relations-and-arrows" class="subheading-anchor" aria-label="Permalink for this section"></a></h5> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-yellow-100 nx-bg-yellow-50 nx-text-yellow-900 dark:nx-border-yellow-200/30 dark:nx-bg-yellow-700/30 dark:nx-text-yellow-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"">⚠️</div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Arrows operate on the <strong>object</strong> of the subject(s) found on a <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">relation</code>. They <em>do not</em> operate on the relation/permission of a subject, <em>even if the subject refers to a relation or permission</em>.</p></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, in:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="text" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="text" data-theme="default"><span class="line"><span style="color:var(--shiki-color-text)">defintion resource {</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> relation parent: group#member</span></span> <span class="line"><span style="color:var(--shiki-color-text)"> permission someperm = parent->something</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent->something</code> refers to the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">something</code> permission on the <strong>group</strong>, and <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">#member</code> will be ignored for the arrow.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">It is recommended to not use arrows over relations that allow for subject relations without noting that fact via a comment.</p> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Why is this the case? In one word: <strong>performance</strong>. If arrows operated over the subject's relation or permission, a full LookupSubjects call would be necessary for the arrow to correctly "walk", which would make these CheckPermission requests potentially <em>incredibly</em> expensive.</p></div></div> <h4 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-xl">.any (Arrow)<a href="#any-arrow" id="any-arrow" class="subheading-anchor" aria-label="Permalink for this section"></a></h4> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">.any</code> is an alias for the standard arrow operation. Arrows allow for "walking" the hierarchy of a subject object's relations and permissions and reference a permission or relation on the resulting subject's object.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent_folder.any(read)</code> is equivalent to <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent_folder->read</code>:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">folder</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">parent_folder:</span><span style="color:var(--shiki-color-text)"> folder</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">reader:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">+</span><span style="color:var(--shiki-color-text)"> parent_folder</span><span style="color:var(--shiki-token-string-expression)">-></span><span style="color:var(--shiki-color-text)">read</span></span> <span class="line highlighted"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> read_same </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> reader </span><span style="color:var(--shiki-token-string-expression)">+</span><span style="color:var(--shiki-color-text)"> </span><span data-rehype-pretty-code-wrapper="true" class="highlighted"><span style="color:var(--shiki-color-text)">parent_folder.</span><span style="color:var(--shiki-token-keyword)">any</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-parameter)">read</span><span style="color:var(--shiki-color-text)">)</span></span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h4 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-xl">.all (Intersection Arrow)<a href="#all-intersection-arrow" id="all-intersection-arrow" class="subheading-anchor" aria-label="Permalink for this section"></a></h4> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">.all</code> defines an <em>intersection</em> arrow: Similar to the standard arrow, it walks over all subjects on the referenced relation to a referenced permission/relation. Unlike the standard arrow, intersection arrow requires that <strong>all</strong> subjects found on the left side of the arrow have the requested permission/relation.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">For example, imagine a schema where a document is viewable by a user if they are a member of any group for the document:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">group</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">member:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">group:</span><span style="color:var(--shiki-color-text)"> group</span></span> <span class="line highlighted"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> view </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> group</span><span style="color:var(--shiki-token-string-expression)">-></span><span style="color:var(--shiki-color-text)">member</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">If the goal was to instead allow documents to be viewable only if the user is a member of <em>all</em> the document's groups, the intersection arrow operator (<code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">.all</code>) could be used:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">user</span><span style="color:var(--shiki-color-text)"> {}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">group</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">member:</span><span style="color:var(--shiki-color-text)"> user</span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span> <span class="line"> </span> <span class="line"><span style="color:var(--shiki-token-keyword)">definition</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-function)">document</span><span style="color:var(--shiki-color-text)"> {</span></span> <span class="line"><span style="color:var(--shiki-token-function)"> relation</span><span style="color:var(--shiki-color-text)"> </span><span style="color:var(--shiki-token-constant)">group:</span><span style="color:var(--shiki-color-text)"> group</span></span> <span class="line highlighted"><span style="color:var(--shiki-token-function)"> permission</span><span style="color:var(--shiki-color-text)"> view </span><span style="color:var(--shiki-token-string-expression)">=</span><span style="color:var(--shiki-color-text)"> </span><span data-rehype-pretty-code-wrapper="true" class="highlighted"><span style="color:var(--shiki-color-text)">group.all(</span><span style="color:var(--shiki-token-parameter)">member</span><span style="color:var(--shiki-color-text)">)</span></span></span> <span class="line"><span style="color:var(--shiki-color-text)">}</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">In the above example, the user must be in the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code> relation for <em>all</em> groups defined on the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">group</code> relation of a document in order to have the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">view</code> permission.</p> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-yellow-100 nx-bg-yellow-50 nx-text-yellow-900 dark:nx-border-yellow-200/30 dark:nx-bg-yellow-700/30 dark:nx-text-yellow-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"">⚠️</div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Intersection arrows can impact performance since they require loading <strong>all</strong> results for the arrow. This is especially a concern for arrows that traverse relationship graphs with a high branching factor. results for the arrow, it can impact performance if the arrow is very wide.</p></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Naming Permissions<a href="#naming-permissions" id="naming-permissions" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Permissions define a set of objects that can perform an action or have some attribute, and thus <strong>permissions should be named as verbs or nouns</strong>, read as <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">(is/can) {permission name} (the object)</code>.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Examples:</p> <table class="nx-block nx-overflow-x-scroll nextra-scrollbar nx-mt-6 nx-p-0 first:nx-mt-0"><thead><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600">Name</th><th class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 nx-font-semibold dark:nx-border-gray-600">Read as</th></tr></thead><tbody><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">read</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">can read the object</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">write</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">can write the object</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">delete</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">can delete the object</td></tr><tr class="nx-m-0 nx-border-t nx-border-gray-300 nx-p-0 dark:nx-border-gray-600 even:nx-bg-gray-100 even:dark:nx-bg-gray-600/20"><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code></td><td class="nx-m-0 nx-border nx-border-gray-300 nx-px-4 nx-py-2 dark:nx-border-gray-600">is member of the object</td></tr></tbody></table> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">You'll note that we also used <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code> above in the relation example. Defining <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">member</code> as a <strong>permission</strong> might be found when you have multiple "ways" a subject can be a member of a resource, thus changing it from a simple relation to a <em>computed</em> set of subjects.</p></div></div> <h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">Comments<a href="#comments" id="comments" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Documentation Comments<a href="#documentation-comments" id="documentation-comments" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">It is <strong>highly</strong> recommended to put doc comments on all definitions, relations and permissions.</p></div></div> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-comment)">/**</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> * something has some doc comment</span></span> <span class="line"><span style="color:var(--shiki-token-comment)"> */</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Non-doc comments<a href="#non-doc-comments" id="non-doc-comments" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="zed" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="zed" data-theme="default"><span class="line"><span style="color:var(--shiki-token-comment)">// Some comment</span></span> <span class="line"><span style="color:var(--shiki-token-comment)">/* Some comment */</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">Full Example<a href="#full-example" id="full-example" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <div><iframe style="width:100%;border:0px;height:500px" src="https://play.authzed.com/i/vlduOcwEOmVY"></iframe></div> <h2 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">Common Patterns<a href="#common-patterns" id="common-patterns" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Group membership<a href="#group-membership" id="group-membership" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Apply specific users or members of a group to a permission on an object type.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">In this example, a group can have users as admins and as members. Both admins and members are considered to have membership in the group. A role can be applied to individual users and groups. All individually applied users as well as members for applied groups will have the <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">allowed</code> permission.</p> <div><iframe style="width:100%;border:0px;height:500px" src="https://play.authzed.com/i/CNe3PXNuhypm"></iframe></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Global admin permissions<a href="#global-admin-permissions" id="global-admin-permissions" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Given an organizational hierarchy of objects where (regular) admin users may exist for a single level of the hierarchy, apply permissions for a set of super-admin users that span across all levels of the hierarchy.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">In lieu of adding a <code>super_admin</code> relation on every object that can be administered, add a root object to the hierarchy, in this example <code>platform</code>. Super admin users can be applied to <code>platform</code> and a relation to <code>platform</code> on top level objects. Admin permission on resources is then defined as the direct owner of the resource as well as through a traversal of the object hierarchy to the platform super admin.</p> <div><iframe style="width:100%;border:0px;height:500px" src="https://play.authzed.com/i/m1lRfaaYf9XP"></iframe></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Synthetic relations<a href="#synthetic-relations" id="synthetic-relations" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Relation traversals can be modeled using intermediate, synthetic relations.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Given the example hierarchy, portfolio can have folders, folders can have documents, we’d like a viewer of a portfolio to also be able to read documents contained in its folders. The read on documents could be thought of as:</p> <div class="nextra-code-block nx-relative nx-mt-6 first:nx-mt-0"><pre class="nx-bg-primary-700/5 nx-mb-4 nx-overflow-x-auto nx-rounded-xl nx-subpixel-antialiased dark:nx-bg-primary-300/10 nx-text-[.9em] contrast-more:nx-border contrast-more:nx-border-primary-900/20 contrast-more:nx-contrast-150 contrast-more:dark:nx-border-primary-100/40 nx-py-4" data-language="text" data-theme="default"><code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr" data-language="text" data-theme="default"><span class="line"><span style="color:var(--shiki-color-text)">reader + parent_folder->reader + parent_folder->parent_portfolio->read</span></span></code></pre><div class="nx-opacity-0 nx-transition [div:hover>&]:nx-opacity-100 focus-within:nx-opacity-100 nx-flex nx-gap-1 nx-absolute nx-m-[11px] nx-right-0 nx-top-0"><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50 md:nx-hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="nx-pointer-events-none nx-h-4 nx-w-4"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button><button class="nextra-button nx-transition-all active:nx-opacity-50 nx-bg-primary-700/5 nx-border nx-border-black/5 nx-text-gray-600 hover:nx-text-gray-900 nx-rounded-md nx-p-1.5 dark:nx-bg-primary-300/10 dark:nx-border-white/10 dark:nx-text-gray-400 dark:hover:nx-text-gray-50" title="Copy code" tabindex="0"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="nextra-copy-icon nx-pointer-events-none nx-h-4 nx-w-4"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M5 15H4C2.89543 15 2 14.1046 2 13V4C2 2.89543 2.89543 2 4 2H13C14.1046 2 15 2.89543 15 4V5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg></button></div></div> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Synthetic relations can simulate multiple walks across permissions and relations.</p> <div><iframe style="width:100%;border:0px;height:500px" src="https://play.authzed.com/i/_VZkOgNX6xfw"></iframe></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Recursive permissions<a href="#recursive-permissions" id="recursive-permissions" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Given a nested set of objects, apply a permission on an object to its descendant objects.</p> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">In this example, a folder can have users with read permission. Additionally, users that can read the parent folder can also read the current folder. Checking read permission on a folder will recursively consider these relations as the answer is computed.</p> <div><iframe style="width:100%;border:0px;height:500px" src="https://play.authzed.com/i/8tE13O7iMM8W"></iframe></div> <div class="nextra-callout nx-overflow-x-auto nx-mt-6 nx-flex nx-rounded-lg nx-border nx-py-2 ltr:nx-pr-4 rtl:nx-pl-4 contrast-more:nx-border-current contrast-more:dark:nx-border-current nx-border-blue-200 nx-bg-blue-100 nx-text-blue-900 dark:nx-border-blue-200/30 dark:nx-bg-blue-900/30 dark:nx-text-blue-200"><div class="nx-select-none nx-text-xl ltr:nx-pl-3 ltr:nx-pr-2 rtl:nx-pr-3 rtl:nx-pl-2" style="font-family:"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" class="nx-mt-1"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"></path></svg></div><div class="nx-w-full nx-min-w-0 nx-leading-7"><p class="nx-mt-6 nx-leading-7 first:nx-mt-0">Note that since <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">parent->read</code> calls the same <code class="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10" dir="ltr">read</code> permission, it will form a recursive lookup across the chain of parent folder(s).</p></div></div> <h3 class="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-8 nx-text-2xl">Recursive permissions across different resource types<a href="#recursive-permissions-across-different-resource-types" id="recursive-permissions-across-different-resource-types" class="subheading-anchor" aria-label="Permalink for this section"></a></h3> <p class="nx-mt-6 nx-leading-7 first:nx-mt-0">If a non-recursive resource is used as the starting point for a recursive lookup, it is <strong>very important</strong> that the permission name used on the right side of the arrow is the <strong>same</strong> in both the starting resource type and the parent resource type(s):</p> <div><iframe style="width:100%;border:0px;height:500px" src="https://play.authzed.com/i/EWVhjM3vGxE6"></iframe></div><div class="nx-mt-16"></div><div class="nx-mb-8 nx-flex nx-items-center nx-border-t nx-pt-8 dark:nx-border-neutral-800 contrast-more:nx-border-neutral-400 dark:contrast-more:nx-border-neutral-400 print:nx-hidden"><a title="Reflection APIs" class="nx-flex nx-max-w-[50%] nx-items-center nx-gap-1 nx-py-4 nx-text-base nx-font-medium nx-text-gray-600 nx-transition-colors [word-break:break-word] hover:nx-text-primary-600 dark:nx-text-gray-300 md:nx-text-lg ltr:nx-pr-4 rtl:nx-pl-4" href="/docs/spicedb/concepts/reflection-apis"><svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-inline nx-h-5 nx-shrink-0 ltr:nx-rotate-180"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>Reflection APIs</a><a title="Operator" class="nx-flex nx-max-w-[50%] nx-items-center nx-gap-1 nx-py-4 nx-text-base nx-font-medium nx-text-gray-600 nx-transition-colors [word-break:break-word] hover:nx-text-primary-600 dark:nx-text-gray-300 md:nx-text-lg ltr:nx-ml-auto ltr:nx-pl-4 ltr:nx-text-right rtl:nx-mr-auto rtl:nx-pr-4 rtl:nx-text-left" href="/docs/spicedb/concepts/operator">Operator<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="nx-inline nx-h-5 nx-shrink-0 rtl:nx-rotate-180"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg></a></div></main></article></div><div class="nx-border-t nx-border-neutral-800 dark:nx-border-neutral-800 bg-neutral-100 dark:nx-bg-neutral-900 print:nx-bg-transparent nx-pb-[env(safe-area-inset-bottom)]"><div class="nx-mx-auto nx-flex nx-max-w-[90rem] nx-justify-center nx-py-12 nx-text-gray-600 dark:nx-text-gray-400 md:nx-justify-start nx-pl-[max(env(safe-area-inset-left),1.5rem)] nx-pr-[max(env(safe-area-inset-right),1.5rem)]"><div class="class="flex w-full flex-col items-center sm:items-start""><div class="w-[3rem] h-[3rem]"><a title="AuthZed" href="https://authzed.com"><svg viewBox="0 0 196 137" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M166.096 71.4542C165.51 82.4278 162.217 93.3718 156.61 102.83C147.219 118.676 131.485 131.052 111.486 134.805C101.502 136.597 94.2404 136.37 86.0852 135.119C80.2022 133.809 76.4985 129.03 80.4486 123.35C85.2888 116.387 92.1491 111.812 98.9966 107.236C118.97 93.8886 140.186 82.7323 161.598 71.9215C163.992 70.7146 166.264 68.3269 166.096 71.4542Z" fill="#A13974"></path><path d="M180.306 45.8493C185.336 41.8702 190.195 36.7584 193.637 31.2819L193.643 31.2778L193.649 31.2736C197.437 25.2428 195.286 19.7977 188.346 18.1471C180.367 16.2482 173.602 17.0129 165.436 18.1471C163.447 18.4233 162.94 18.8517 162.26 19.2813C160.882 20.1512 160.73 22.807 162.714 23.1376C166.344 23.3645 178.236 22.5522 181.088 23.8181C189.214 27.4257 166.978 39.4369 164.056 41.762C162.303 43.1547 161.463 42.9875 160.477 40.7948C152.744 23.6025 140.151 11.412 122.553 4.49034C111.524 0.154092 100.161 -0.838608 88.4221 0.644988C82.0962 1.44416 77.1335 3.18159 71.3216 5.44573C69.405 6.19237 66.8695 7.46422 65.1062 8.4775C60.9731 10.848 57.1692 13.5068 53.707 16.4688C50.6915 19.0487 52.4627 23.6672 56.414 24.0382L129.164 30.8682C132.393 31.1713 133.988 34.9422 131.958 37.4701L91.3821 89.3527C89.9063 91.1902 91.7907 94.2202 93.9788 93.3445C110.486 86.7196 126.534 78.6799 142.423 70.6907C155.673 64.0281 168.705 55.0251 180.306 45.8493Z" fill="#FB5B62"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M104.73 50.2846C107.32 47.5099 105.039 43.0137 101.27 43.465L35.3704 51.3574C33.3771 51.5961 31.7184 53.0327 31.3161 54.9994C28.7818 67.3874 29.7928 79.8632 34.5611 92.3506C36.3467 97.0287 36.4586 97.1634 31.6384 97.7561C31.0099 97.8333 30.3801 97.9186 29.7493 98.0042C26.1152 98.4968 22.447 98.9941 18.7905 97.9561C9.95196 95.4383 23.5461 87.0659 24.5725 83.4884C25.3304 80.8466 21.7396 79.8571 19.4945 81.4426C12.3004 86.5231 5.4514 92.452 1.20434 100.292C0.296773 102.107 0.40903 104.377 0.750489 105.604C3.26522 114.639 22.7348 112.999 29.1492 111.847C37.5543 110.338 43.6231 109.79 51.7893 107.295C54.0165 106.614 54.0577 106.388 57.4603 102.882C74.7001 86.8794 90.4768 65.0613 104.73 50.2846Z" fill="#EFA16D"></path></svg></a></div><div class="nx-text-xs">© <!-- -->2024<!-- --> AuthZed.</div></div></div><div></div></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/spicedb/concepts/schema","query":{},"buildId":"_qU6EoFbs5qnijdzF7DDY","assetPrefix":"https://docs-authzed.vercel.app/docs","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>