diff --git a/docs-mintlify/docs.json b/docs-mintlify/docs.json
index 6efc41da1c..461747cbd4 100644
--- a/docs-mintlify/docs.json
+++ b/docs-mintlify/docs.json
@@ -57,32 +57,43 @@
"group": "Getting Started",
"pages": [
"docs/getting-started/setup",
- "docs/getting-started/components",
"docs/getting-started/users",
+ "docs/getting-started/components",
"docs/getting-started/production",
"docs/getting-started/vite-example"
]
},
{
- "group": "Apps",
- "pages": [
- "docs/apps/api-keys",
- "docs/apps/emails",
- "docs/apps/oauth",
- "docs/apps/orgs-and-teams",
- "docs/apps/permissions",
- "docs/apps/webhooks",
- "docs/apps/payments",
- "docs/apps/analytics"
- ]
- },
- {
- "group": "Concepts",
+ "group": "Going Further",
"pages": [
+ "docs/going-further/working-with-ai",
+ "docs/concepts/stack-app",
"docs/concepts/backend-integration",
+ "docs/going-further/local-development",
+ {
+ "group": "Component Customization",
+ "pages": [
+ "docs/customization/custom-pages",
+ "docs/customization/custom-styles",
+ "docs/customization/dark-mode",
+ "docs/customization/internationalization",
+ {
+ "group": "Page Examples",
+ "pages": [
+ "docs/customization/page-examples",
+ "docs/customization/page-examples/forgot-password",
+ "docs/customization/page-examples/password-reset",
+ "docs/customization/page-examples/sign-in",
+ "docs/customization/page-examples/sign-up"
+ ]
+ }
+ ]
+ },
"docs/concepts/custom-user-data",
"docs/concepts/sign-up-rules",
"docs/concepts/jwt",
+ "docs/concepts/user-onboarding",
+ "docs/concepts/team-selection",
{
"group": "Auth Providers",
"pages": [
@@ -102,40 +113,46 @@
"docs/concepts/auth-providers/two-factor-auth",
"docs/concepts/auth-providers/x-twitter"
]
- },
- "docs/concepts/stack-app",
- "docs/concepts/team-selection",
- "docs/concepts/user-onboarding"
+ }
]
},
{
- "group": "Customization",
+ "group": "Apps",
"pages": [
- "docs/customization/custom-pages",
- "docs/customization/custom-styles",
- "docs/customization/dark-mode",
- "docs/customization/internationalization",
{
- "group": "Page Examples",
+ "group": "Authentication",
+ "icon": "lock",
"pages": [
- "docs/customization/page-examples",
- "docs/customization/page-examples/forgot-password",
- "docs/customization/page-examples/password-reset",
- "docs/customization/page-examples/sign-in",
- "docs/customization/page-examples/sign-up"
+ "docs/apps/auth-providers",
+ "docs/apps/oauth"
]
- }
+ },
+ "docs/apps/emails",
+ "docs/apps/payments",
+ "docs/apps/analytics",
+ "docs/apps/api-keys",
+ "docs/apps/data-vault",
+ "docs/apps/launch-checklist",
+ "docs/apps/permissions",
+ "docs/apps/orgs-and-teams",
+ "docs/apps/webhooks"
]
},
{
- "group": "Other",
+ "group": "Integrations",
"pages": [
- "docs/others/cli-authentication",
- "docs/others/self-host",
"docs/others/supabase",
"docs/others/convex",
"docs/others/mcp-setup"
]
+ },
+ {
+ "group": "Other",
+ "pages": [
+ "docs/others/self-host",
+ "docs/others/cli-authentication",
+ "docs/going-further/showcase"
+ ]
}
]
},
diff --git a/docs-mintlify/docs/apps/auth-providers.mdx b/docs-mintlify/docs/apps/auth-providers.mdx
index 2ccd61180a..0812c42a0c 100644
--- a/docs-mintlify/docs/apps/auth-providers.mdx
+++ b/docs-mintlify/docs/apps/auth-providers.mdx
@@ -1,7 +1,6 @@
---
title: Auth Providers
description: Configure authentication providers for your application
-icon: shield
---
Stack Auth supports a variety of authentication providers to give your users flexible sign-in options. You can configure these providers through the Stack Auth dashboard.
diff --git a/docs-mintlify/docs/apps/data-vault.mdx b/docs-mintlify/docs/apps/data-vault.mdx
new file mode 100644
index 0000000000..45e7b1e605
--- /dev/null
+++ b/docs-mintlify/docs/apps/data-vault.mdx
@@ -0,0 +1,7 @@
+---
+title: "Data Vault"
+description: "Securely store and manage sensitive data for your application"
+icon: "vault"
+---
+
+This page is under construction. Check back soon for documentation on using the Data Vault.
diff --git a/docs-mintlify/docs/apps/emails.mdx b/docs-mintlify/docs/apps/emails.mdx
index b1e75a120c..ed3466e9d8 100644
--- a/docs-mintlify/docs/apps/emails.mdx
+++ b/docs-mintlify/docs/apps/emails.mdx
@@ -1,7 +1,7 @@
---
title: "Emails"
description: "Send custom emails to your users with Stack Auth's email system."
-icon: "mail"
+icon: "envelope"
---
Stack Auth provides emails that allows you to send custom emails to your users. The system supports both custom HTML emails and template-based emails with theming.
diff --git a/docs-mintlify/docs/apps/launch-checklist.mdx b/docs-mintlify/docs/apps/launch-checklist.mdx
new file mode 100644
index 0000000000..60ac7d5ac1
--- /dev/null
+++ b/docs-mintlify/docs/apps/launch-checklist.mdx
@@ -0,0 +1,7 @@
+---
+title: "Launch Checklist"
+description: "Everything you need to verify before going live with Stack Auth"
+icon: "clipboard-check"
+---
+
+This page is under construction. Check back soon for the launch checklist.
diff --git a/docs-mintlify/docs/apps/oauth.mdx b/docs-mintlify/docs/apps/oauth.mdx
index 529845a005..f3160561bb 100644
--- a/docs-mintlify/docs/apps/oauth.mdx
+++ b/docs-mintlify/docs/apps/oauth.mdx
@@ -1,7 +1,6 @@
---
title: "OAuth"
description: "Managing third-party OAuth access tokens"
-icon: "globe"
---
Stack has good support for working with OAuth and OIDC providers, such as Google, Facebook, Microsoft, and others.
diff --git a/docs-mintlify/docs/getting-started/users.mdx b/docs-mintlify/docs/getting-started/users.mdx
index 57106a31b2..f34cb61ca5 100644
--- a/docs-mintlify/docs/getting-started/users.mdx
+++ b/docs-mintlify/docs/getting-started/users.mdx
@@ -1,54 +1,72 @@
---
-title: Users
+title: User Fundamentals
description: Access and manage user information within custom components
-sidebarTitle: Users
+sidebarTitle: User Fundamentals
icon: "users"
---
+import { UserFieldsTable } from "/snippets/user-fields-table.jsx";
+
# Users
-You will inevitably build custom components that access the user in one way or another. In this section, we will take a closer look at the functions and hooks that let you do this.
+You've set up Stack Auth. Now let's understand the most important object in your application: the **User**.
-## Client Component basics
+The user object represents whoever is currently interacting with your app — their identity, profile, and metadata. Almost everything you build will revolve around it: retrieving the current user, protecting pages from unauthorized access, updating profile information, signing out, and more.
-The `useUser()` hook returns the current user in a Client Component. By default, it will return `null` if the user is not signed in.
+## Getting the current user
-```tsx title="my-client-component.tsx"
-"use client";
-import { useUser } from "@stackframe/stack"
-
-export function MyClientComponent() {
- const user = useUser();
- return
{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}
;
-}
-```
+The way you retrieve the current user depends on whether you're in a Client Component or a Server Component. Both return `null` if the user is not signed in.
-The `useUser()` hook is simply a shorthand for `useStackApp().useUser()`. `useStackApp()` also contains other useful hooks and methods for clients, which will be described later.
+
+
+ Use the `useUser()` hook:
-Sometimes, you want to retrieve the user only if they're signed in, and redirect to the sign-in page otherwise. In this case, simply pass `{ or: "redirect" }`, and the function will never return `null`.
+ ```tsx title="my-client-component.tsx"
+ "use client";
+ import { useUser } from "@stackframe/stack"
-```tsx
-const user = useUser({ or: "redirect" });
-return
{`Hello, ${user.displayName ?? "anon"}`}
;
-```
+ export function MyClientComponent() {
+ const user = useUser();
+ return
{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}
;
+ }
+ ```
-## Server Component basics
+ The `useUser()` hook is simply a shorthand for `useStackApp().useUser()`. `useStackApp()` also contains other useful hooks and methods for clients, which will be described later. Since it's a React hook, your component will automatically re-render when the user changes (e.g. on sign-out).
+
+
+ Since `useUser()` is a stateful hook, you can't use it in Server Components. Instead, import `stackServerApp` from `stack/server.ts` and call `getUser()`:
-Since `useUser()` is a stateful hook, you can't use it on server components. Instead, you can import `stackServerApp` from `stack/server.ts` and call `getUser()`:
+ ```tsx title="my-server-component.tsx"
+ import { stackServerApp } from "@/stack/server";
-```tsx title="my-server-component.tsx"
-import { stackServerApp } from "@/stack/server";
+ export default async function MyServerComponent() {
+ const user = await stackServerApp.getUser();
+ return
{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}
{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}
;
-}
-```
+ Unlike `useUser()`, `getUser()` fetches the user once at request time and does not re-render on changes. You can also call `useStackApp().getUser()` on the client side to get the user in a non-component context.
+
+
Since `useUser()` is a hook, it will re-render the component on user changes (eg. signout), while `getUser()` will only fetch the user once (on page load). You can also call `useStackApp().getUser()` on the client side to get the user in a non-component context.
+### Requiring a signed-in user
+
+Sometimes, you want to retrieve the user only if they're signed in, and redirect to the sign-in page otherwise. In this case, simply pass `{ or: "redirect" }`, and the function will never return `null`.
+
+You can also use `{ or: "throw" }` to throw an error instead — useful in API routes and server actions where a redirect doesn't make sense.
+
+In both cases, the return type is non-nullable, so you don't need to handle `null`.
+
+```tsx
+const user = useUser({ or: "redirect" });
+// user is guaranteed to be non-null here
+return
{`Hello, ${user.displayName ?? "anon"}`}
;
+```
+
## Protecting a page
There are three ways to protect a page: in Client Components with `useUser({ or: "redirect" })`, in Server Components with `await getUser({ or: "redirect" })`, or with middleware.
@@ -116,6 +134,16 @@ Middleware can be used whenever it is easy to tell whether a page should be prot
## User data
+### What's on a user object?
+
+Before diving into updates, here's an overview of the most important fields available on every user:
+
+
+
+For the full list of fields and methods, see the [User SDK reference](../sdk/types/user).
+
+### Updating a user
+
You can update attributes on a user object with the `user.update()` function.
```tsx title="my-client-component.tsx"
@@ -130,7 +158,52 @@ export default function MyClientComponent() {
}
```
-You can also store custom user data in the `clientMetadata`, `serverMetadata`, or `clientReadOnlyMetadata` fields. More information [here](../concepts/custom-user-data).
+### Custom metadata
+
+Beyond built-in fields like `displayName` and `primaryEmail`, you'll often need to store your own data on a user. Stack Auth provides three metadata fields for this:
+
+- **`clientMetadata`** — Readable and writable from both the client and the server. Use this for non-sensitive user preferences like theme, locale, or UI state.
+- **`serverMetadata`** — Readable and writable only from the server. Use this for sensitive or internal data like Stripe customer IDs, internal flags, or anything users shouldn't be able to see or modify.
+- **`clientReadOnlyMetadata`** — Readable from the client, writable only from the server. Use this for data the client needs to display but shouldn't be able to change, like subscription plans or role labels.
+
+For example, storing a user's theme preference in `clientMetadata`:
+
+```tsx title="theme-toggle.tsx"
+'use client';
+import { useUser } from "@stackframe/stack";
+
+export default function ThemeToggle() {
+ const user = useUser({ or: "redirect" });
+ const currentTheme = user.clientMetadata?.theme ?? "light";
+
+ return (
+
+ );
+}
+```
+
+And storing sensitive data in `serverMetadata` (server-side only):
+
+```tsx title="server-example.ts"
+const user = await stackServerApp.getUser({ or: "throw" });
+await user.update({
+ serverMetadata: {
+ ...user.serverMetadata,
+ stripeCustomerId: "cus_abc123",
+ },
+});
+```
+
+For more details, see the [Custom User Data](../concepts/custom-user-data) documentation.
## Signing out
@@ -228,6 +301,37 @@ After saving your code, you can see the profile page on [http://localhost:3000/p
For more examples on how to use the `User` object, check the [the SDK documentation](../sdk/types/user).
+## Anonymous users
+
+Stack Auth supports anonymous users - users who can interact with your app without signing up. This is useful for features like guest checkouts, try-before-you-sign-up flows, or collecting analytics before a user creates an account.
+
+To get an anonymous user, pass `{ or: "anonymous" }` to `useUser()` or `getUser()`. If the current visitor isn't signed in, Stack will automatically create an anonymous account for them behind the scenes.
+
+```tsx title="my-client-component.tsx"
+"use client";
+import { useUser } from "@stackframe/stack";
+
+export default function MyComponent() {
+ const user = useUser({ or: "anonymous" });
+ // user is always non-null — either a real user or an anonymous one
+ return
Your user ID: {user.id}
;
+}
+```
+
+Anonymous users have an `isAnonymous` property set to `true` and are also considered restricted (`isRestricted` is `true`). You can check this to show different UI for anonymous vs. signed-in users:
+
+```tsx
+const user = useUser({ or: "anonymous" });
+if (user.isAnonymous) {
+ return
You're browsing as a guest. Create an account to save your progress.
;
+}
+return
Welcome back, {user.displayName}!
;
+```
+
+
+ When using `{ or: "anonymous" }`, the `includeRestricted` option is automatically set to `true`, since all anonymous users are restricted by definition. You cannot use `{ or: "anonymous" }` with `{ includeRestricted: false }`.
+
+
## Next steps
In the next guide, we will show you how to put [your application into production](./production).
diff --git a/docs-mintlify/docs/going-further/local-development.mdx b/docs-mintlify/docs/going-further/local-development.mdx
new file mode 100644
index 0000000000..58f3294398
--- /dev/null
+++ b/docs-mintlify/docs/going-further/local-development.mdx
@@ -0,0 +1,6 @@
+---
+title: "Local Development"
+description: "Set up and run Stack Auth locally for development and testing"
+---
+
+This page is under construction. Check back soon for instructions on setting up Stack Auth for local development.
diff --git a/docs-mintlify/docs/going-further/showcase.mdx b/docs-mintlify/docs/going-further/showcase.mdx
new file mode 100644
index 0000000000..1ea3af6c1e
--- /dev/null
+++ b/docs-mintlify/docs/going-further/showcase.mdx
@@ -0,0 +1,6 @@
+---
+title: "Showcase"
+description: "See what others have built with Stack Auth"
+---
+
+This page is under construction. Check back soon for a showcase of projects and applications built with Stack Auth.
diff --git a/docs-mintlify/docs/going-further/working-with-ai.mdx b/docs-mintlify/docs/going-further/working-with-ai.mdx
new file mode 100644
index 0000000000..ef5c7a43d9
--- /dev/null
+++ b/docs-mintlify/docs/going-further/working-with-ai.mdx
@@ -0,0 +1,6 @@
+---
+title: "Working with AI"
+description: "Use AI-powered tools and integrations with Stack Auth to accelerate your development workflow"
+---
+
+This page is under construction. Check back soon for guidance on integrating Stack Auth with AI-powered development tools.
diff --git a/docs-mintlify/snippets/user-fields-table.jsx b/docs-mintlify/snippets/user-fields-table.jsx
new file mode 100644
index 0000000000..a81784815f
--- /dev/null
+++ b/docs-mintlify/snippets/user-fields-table.jsx
@@ -0,0 +1,39 @@
+export const UserFieldsTable = () => {
+ const fields = [
+ { name: "id", type: "string", description: "Unique identifier — always use this for lookups, not email" },
+ { name: "displayName", type: "string | null", description: "The user's display name" },
+ { name: "primaryEmail", type: "string | null", description: "The user's email address (not guaranteed unique)" },
+ { name: "primaryEmailVerified", type: "boolean", description: "Whether the email has been verified" },
+ { name: "profileImageUrl", type: "string | null", description: "URL to the user's profile image" },
+ { name: "signedUpAt", type: "Date", description: "When the user created their account" },
+ { name: "clientMetadata", type: "any", description: "Custom data, readable/writable from client and server" },
+ { name: "clientReadOnlyMetadata", type: "any", description: "Custom data, readable from client, writable only from server" },
+ { name: "serverMetadata", type: "any", description: "Custom data, server-only (only on server-side user objects)" },
+ { name: "hasPassword", type: "boolean", description: "Whether the user has a password set" },
+ { name: "isAnonymous", type: "boolean", description: "Whether this is an anonymous user" },
+ { name: "isRestricted", type: "boolean", description: "Hasn't completed onboarding requirements (e.g. email not verified)" },
+ ];
+
+ return (
+