Google Antigravity Directory

The #1 directory for Google Antigravity prompts, rules, workflows & MCP servers. Optimized for Gemini 3 agentic development.

Resources

PromptsMCP ServersAntigravity RulesGEMINI.md GuideBest Practices

Company

Submit PromptAntigravityAI.directory

Popular Prompts

Next.js 14 App RouterReact TypeScriptTypeScript AdvancedFastAPI GuideDocker Best Practices

Legal

Privacy PolicyTerms of ServiceContact Us
Featured on FazierFeatured on WayfindioAntigravity AI - Featured on Startup FameFeatured on Wired BusinessFeatured on Twelve ToolsListed on Turbo0Featured on findly.toolsFeatured on Aura++That App ShowAI ToolzShinyLaunchMillion Dot HomepageSolver ToolsFeatured on FazierFeatured on WayfindioAntigravity AI - Featured on Startup FameFeatured on Wired BusinessFeatured on Twelve ToolsListed on Turbo0Featured on findly.toolsFeatured on Aura++That App ShowAI ToolzShinyLaunchMillion Dot HomepageSolver Tools

© 2026 Antigravity AI Directory. All rights reserved.

The #1 directory for Google Antigravity IDE

This website is not affiliated with, endorsed by, or associated with Google LLC. "Google" and "Gemini" are trademarks of Google LLC.

Antigravity AI Directory
PromptsMCPBest PracticesUse CasesLearn
Home
Prompts
Clerk Organizations Multi-Tenancy

Clerk Organizations Multi-Tenancy

Multi-tenant applications with Clerk Organizations for Google Antigravity projects including team management, roles, and permissions.

clerkmulti-tenancyorganizationsrbacnextjs
by Antigravity Team
⭐0Stars
.antigravity
# Clerk Organizations Multi-Tenancy for Google Antigravity

Build multi-tenant applications with Clerk Organizations in your Google Antigravity IDE projects. This comprehensive guide covers organization management, role-based access control, and team collaboration patterns optimized for Gemini 3 agentic development.

## Clerk Configuration

Set up Clerk with organization support:

```typescript
// lib/clerk.ts
import { clerkClient } from '@clerk/nextjs/server';

// Organization role definitions
export const ORGANIZATION_ROLES = {
  owner: {
    name: 'Owner',
    permissions: ['*'],
    description: 'Full access to organization settings and resources',
  },
  admin: {
    name: 'Admin',
    permissions: [
      'org:manage_members',
      'org:manage_settings',
      'prompts:create',
      'prompts:edit',
      'prompts:delete',
      'prompts:publish',
    ],
    description: 'Manage members and all prompts',
  },
  member: {
    name: 'Member',
    permissions: [
      'prompts:create',
      'prompts:edit_own',
      'prompts:delete_own',
    ],
    description: 'Create and manage own prompts',
  },
  viewer: {
    name: 'Viewer',
    permissions: ['prompts:view'],
    description: 'View-only access to prompts',
  },
} as const;

export type OrganizationRole = keyof typeof ORGANIZATION_ROLES;

export function hasPermission(
  userPermissions: string[],
  requiredPermission: string
): boolean {
  return (
    userPermissions.includes('*') ||
    userPermissions.includes(requiredPermission)
  );
}
```

## Middleware Setup

Protect routes based on organization membership:

```typescript
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

const isPublicRoute = createRouteMatcher([
  '/',
  '/prompts(.*)',
  '/api/public(.*)',
  '/sign-in(.*)',
  '/sign-up(.*)',
]);

const isOrgRoute = createRouteMatcher([
  '/org/(.*)',
  '/api/org/(.*)',
  '/dashboard(.*)',
]);

export default clerkMiddleware((auth, request) => {
  if (!isPublicRoute(request)) {
    auth().protect();
  }

  if (isOrgRoute(request)) {
    auth().protect({
      // Require active organization for org routes
      unauthenticatedUrl: '/sign-in',
      unauthorizedUrl: '/select-organization',
    });
  }
});

export const config = {
  matcher: ['/((?!.*\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};
```

## Organization Context Provider

Manage organization state in React:

```typescript
// contexts/OrganizationContext.tsx
'use client';

import { createContext, useContext, useMemo } from 'react';
import { useOrganization, useOrganizationList } from '@clerk/nextjs';
import { ORGANIZATION_ROLES, hasPermission } from '@/lib/clerk';

interface OrganizationContextType {
  organization: ReturnType<typeof useOrganization>['organization'];
  membership: ReturnType<typeof useOrganization>['membership'];
  isLoaded: boolean;
  permissions: string[];
  hasPermission: (permission: string) => boolean;
  isOwner: boolean;
  isAdmin: boolean;
}

const OrganizationContext = createContext<OrganizationContextType | null>(null);

export function OrganizationProvider({ children }: { children: React.ReactNode }) {
  const { organization, membership, isLoaded } = useOrganization();

  const role = membership?.role as keyof typeof ORGANIZATION_ROLES | undefined;
  const permissions = role ? ORGANIZATION_ROLES[role]?.permissions ?? [] : [];

  const value = useMemo(
    () => ({
      organization,
      membership,
      isLoaded,
      permissions,
      hasPermission: (permission: string) => hasPermission(permissions, permission),
      isOwner: role === 'owner',
      isAdmin: role === 'owner' || role === 'admin',
    }),
    [organization, membership, isLoaded, permissions, role]
  );

  return (
    <OrganizationContext.Provider value={value}>
      {children}
    </OrganizationContext.Provider>
  );
}

export function useOrg() {
  const context = useContext(OrganizationContext);
  if (!context) {
    throw new Error('useOrg must be used within OrganizationProvider');
  }
  return context;
}
```

## Organization Management Components

Build team management interfaces:

```typescript
// components/organization/InviteMembers.tsx
'use client';

import { useState } from 'react';
import { useOrganization } from '@clerk/nextjs';
import { OrganizationRole, ORGANIZATION_ROLES } from '@/lib/clerk';

export function InviteMembers() {
  const { organization } = useOrganization();
  const [email, setEmail] = useState('');
  const [role, setRole] = useState<OrganizationRole>('member');
  const [isLoading, setIsLoading] = useState(false);
  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);

  const handleInvite = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!organization) return;

    setIsLoading(true);
    setMessage(null);

    try {
      await organization.inviteMember({
        emailAddress: email,
        role,
      });

      setMessage({ type: 'success', text: `Invitation sent to ${email}` });
      setEmail('');
    } catch (error) {
      setMessage({
        type: 'error',
        text: error instanceof Error ? error.message : 'Failed to send invitation',
      });
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="invite-members">
      <h3>Invite Team Members</h3>
      <form onSubmit={handleInvite}>
        <div className="form-group">
          <label htmlFor="email">Email Address</label>
          <input
            type="email"
            id="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            placeholder="colleague@company.com"
            required
          />
        </div>

        <div className="form-group">
          <label htmlFor="role">Role</label>
          <select
            id="role"
            value={role}
            onChange={(e) => setRole(e.target.value as OrganizationRole)}
          >
            {Object.entries(ORGANIZATION_ROLES).map(([key, config]) => (
              <option key={key} value={key}>
                {config.name} - {config.description}
              </option>
            ))}
          </select>
        </div>

        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Sending...' : 'Send Invitation'}
        </button>

        {message && (
          <p className={`message ${message.type}`}>{message.text}</p>
        )}
      </form>
    </div>
  );
}

// components/organization/MembersList.tsx
'use client';

import { useOrganization } from '@clerk/nextjs';
import { useOrg } from '@/contexts/OrganizationContext';

export function MembersList() {
  const { membershipList, isLoaded } = useOrganization({
    membershipList: { limit: 100 },
  });
  const { isAdmin } = useOrg();

  if (!isLoaded) return <MembersListSkeleton />;

  return (
    <div className="members-list">
      <h3>Team Members ({membershipList?.length || 0})</h3>
      <ul>
        {membershipList?.map((membership) => (
          <li key={membership.id} className="member-item">
            <img
              src={membership.publicUserData.imageUrl}
              alt={membership.publicUserData.firstName || 'Member'}
              className="avatar"
            />
            <div className="member-info">
              <span className="name">
                {membership.publicUserData.firstName}{' '}
                {membership.publicUserData.lastName}
              </span>
              <span className="role">{membership.role}</span>
            </div>
            {isAdmin && membership.role !== 'owner' && (
              <MemberActions membership={membership} />
            )}
          </li>
        ))}
      </ul>
    </div>
  );
}
```

## API Route Protection

Protect API routes with organization checks:

```typescript
// app/api/org/prompts/route.ts
import { auth } from '@clerk/nextjs/server';
import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { hasPermission, ORGANIZATION_ROLES } from '@/lib/clerk';

export async function POST(request: NextRequest) {
  const { userId, orgId, orgRole } = auth();

  if (!userId || !orgId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const role = orgRole as keyof typeof ORGANIZATION_ROLES;
  const permissions = ORGANIZATION_ROLES[role]?.permissions ?? [];

  if (!hasPermission(permissions, 'prompts:create')) {
    return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
  }

  const body = await request.json();

  const prompt = await db.prompt.create({
    data: {
      ...body,
      organizationId: orgId,
      authorId: userId,
    },
  });

  return NextResponse.json(prompt);
}
```

## Best Practices

1. **Define clear role hierarchies** with specific permissions
2. **Use Clerk components** for organization switching UI
3. **Implement audit logging** for organization changes
4. **Cache organization data** to reduce API calls
5. **Handle organization switching** gracefully in UI
6. **Set up webhooks** for organization events
7. **Implement resource quotas** per organization tier

When to Use This Prompt

This clerk prompt is ideal for developers working on:

  • clerk applications requiring modern best practices and optimal performance
  • Projects that need production-ready clerk code with proper error handling
  • Teams looking to standardize their clerk development workflow
  • Developers wanting to learn industry-standard clerk patterns and techniques

By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their clerk implementations.

How to Use

  1. Copy the prompt - Click the copy button above to copy the entire prompt to your clipboard
  2. Paste into your AI assistant - Use with Claude, ChatGPT, Cursor, or any AI coding tool
  3. Customize as needed - Adjust the prompt based on your specific requirements
  4. Review the output - Always review generated code for security and correctness
💡 Pro Tip: For best results, provide context about your project structure and any specific constraints or preferences you have.

Best Practices

  • ✓ Always review generated code for security vulnerabilities before deploying
  • ✓ Test the clerk code in a development environment first
  • ✓ Customize the prompt output to match your project's coding standards
  • ✓ Keep your AI assistant's context window in mind for complex requirements
  • ✓ Version control your prompts alongside your code for reproducibility

Frequently Asked Questions

Can I use this clerk prompt commercially?

Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.

Which AI assistants work best with this prompt?

This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.

How do I customize this prompt for my specific needs?

You can modify the prompt by adding specific requirements, constraints, or preferences. For clerk projects, consider mentioning your framework version, coding style, and any specific libraries you're using.

Related Prompts

💬 Comments

Loading comments...