Friday, January 10th 2025
Multi-Organization & Monorepo
Announcing the latest version of Achromatic with multi-organization support and monorepo integration, providing better project management and improved development workflows.
We’re excited to introduce multi-organization support and Turborepo in Achromatic! This update enables users to seamlessly manage and switch between multiple organizations while improving project structure and performance with Turborepo. The changes include database updates, UI refinements, business logic enhancements and a more modular architecture.
Features
1. Organization Management
- Create, update, delete, and search organizations.
- Upload or remove organization logos.
- Invite and manage members within an organization.
- Transfer ownership of an organization.
- Identify organizations by a slug.
2. Organization Switching
- Switch between organizations using a dropdown or menu.
- Derive organization context from the slug.
3. UI/UX Updates
- Updated navigation and layouts to support multi-organization views.
- Context-aware components, data functions, and server actions.
- A design approach similar to Linear, Campsite, and Stripe.
Key Changes
- New Membership Table: Tracks user roles and organization access.
- Auth.js Simplicity: No more
organizationId
in sessions; organizations derive from slugs. - Organization Enhancements: Removed
completedOnboarding
, addedslug
andlogo
and introducedOrganizationLogo
. - Streamlined Onboarding: New invitation step and reduced component complexity.
- Sidebar Redesign: More intuitive settings layout and improved space efficiency.
- UI Refinements: Text adjustments for better density and readability.
- Improved Invitation Flow: No more "join" action; users sign in with their invited email.
- New replaceOrgSlug() Helper: Simplifies route construction for organizations.
- Organization-Specific Caching: Ensures data integrity across different organizations.
- Refactored Authentication & Context Handling: Removed
@/lib/auth/organizations.ts
, replacing it with context-based authentication. - Added Turborepo support for better modularization and performance.
- Overhauled the auth pages with a new desig
- Minimized env variables (and ensured consistent naming).
- Improved the sidebar resize, collapse and animation state.
Context Handling
Achromatic now uses structured context retrieval for both actions and data functions to ensure seamless organization-aware workflows.
1. Actions
Example: Adding a contact with authOrganizationActionClient
export const addContact = authOrganizationActionClient .metadata({ actionName: 'addContact' }) .schema(addContactSchema) .action(async ({ parsedInput, ctx }) => { const user = ctx.session.user; const organizationId = ctx.organization.id; const memberships = ctx.organization.memberships; });
2. Data Functions
Fetching contact details with getAuthOrganizationContext
:
export async function getContact(input: GetContactSchema): Promise<ContactDto> { const ctx = await getAuthOrganizationContext(); const user = ctx.session.user; const organizationId = ctx.organization.id;}
3. Standard Authentication Context
Used outside an organization context (e.g., onboarding):
export async function getSomeData(): Promise<Data> { const ctx = await getAuthContext(); const user = ctx.session.user;}
Middleware: Automatic Slug Handling
To avoid passing organization slugs manually through components, we introduced a middleware that automatically attaches the organization slug as a request header.
export function middleware(request: NextRequest) { const pathSegments = request.nextUrl.pathname.split('/').filter(Boolean); let slug = pathSegments.length >= 2 && pathSegments[0] === 'organizations' ? pathSegments[1] : null; const response = NextResponse.next(); if (slug) response.headers.set('x-organization-slug', slug); return response;}export const config = { matcher: ['/organizations/:path*'] };
Provider & Hook
A new useActiveOrganization
hook provides quick access to the active organization in client components.
'use client';export function Component(): React.JSX.Element { const activeOrganization = useActiveOrganization(); return <>{activeOrganization.name}</>;}
Screenshots





