Bird
Raised Fist0
Remixframework~20 mins

Multi-tenant applications in Remix - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Multi-tenant Remix Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ component_behavior
intermediate
2:00remaining
How does Remix handle tenant-specific data loading?

Consider a Remix loader function that fetches data based on the tenant ID from the URL params. What will the loader return if the tenant ID is missing?

Remix
import { json } from '@remix-run/node';

export async function loader({ params }) {
  const tenantId = params.tenantId;
  if (!tenantId) {
    return new Response('Tenant ID missing', { status: 400 });
  }
  const data = await fetchTenantData(tenantId);
  return json(data);
}
AIt returns an empty JSON object {}.
BIt throws a runtime error because tenantId is undefined.
CIt returns a 400 response with message 'Tenant ID missing'.
DIt returns data for a default tenant.
Attempts:
2 left
💡 Hint

Check the condition that handles missing tenantId in the loader.

❓ state_output
intermediate
2:00remaining
Tenant context propagation in Remix components

Given a Remix app that uses a React context to store tenant info, what will be the value of tenantId inside a child component if the context provider is missing?

Remix
import React from 'react';

const TenantContext = React.createContext(null);

function ChildComponent() {
  const tenantId = React.useContext(TenantContext);
  return <div>{tenantId ?? 'No tenant'}</div>;
}
AThe component renders 'No tenant'.
BThe component throws an error because context is undefined.
CThe component renders 'null'.
DThe component renders an empty string.
Attempts:
2 left
💡 Hint

What is the default value of the context?

📝 Syntax
advanced
2:00remaining
Correct syntax for tenant-aware route in Remix

Which route file name correctly defines a dynamic tenant segment in Remix?

Aroutes/$tenantId/index.tsx
Broutes/:tenantId/index.tsx
Croutes/tenantId/index.tsx
Droutes/[tenantId]/index.tsx
Attempts:
2 left
💡 Hint

Remix uses a specific syntax for dynamic route segments.

🔧 Debug
advanced
2:00remaining
Why does tenant data not update on route change?

A Remix app fetches tenant data in a loader using params.tenantId. When navigating between tenants, the UI does not update with new tenant data. What is the likely cause?

Remix
import { json } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';

export async function loader({ params }) {
  const tenantId = params.tenantId;
  return json(await fetchTenantData(tenantId));
}

export default function TenantPage() {
  const data = useLoaderData();
  return <div>{data.name}</div>;
}
AfetchTenantData caches data and returns stale results.
BThe route path is not dynamic, so loader is not re-run on tenantId change.
CuseLoaderData is used incorrectly inside the component.
Dparams.tenantId is undefined because of a typo.
Attempts:
2 left
💡 Hint

Check if the route file name matches the dynamic segment.

🧠 Conceptual
expert
3:00remaining
Best practice for tenant isolation in Remix loaders

In a multi-tenant Remix app, what is the best way to ensure tenant data isolation in loaders?

AUse a single loader for all tenants and switch data based on user session.
BFetch all tenants' data once and filter in the component based on tenantId.
CStore tenant data globally in a React context and share across loaders.
DValidate tenantId from params and fetch data only for that tenant inside each loader.
Attempts:
2 left
💡 Hint

Think about security and data separation at the data fetching level.

Practice

(1/5)
1. What is the main purpose of a multi-tenant application in Remix Framework?
easy
A. To run multiple Remix apps on different servers
B. To create multiple copies of the same app for each user
C. To allow users to share the same data across all tenants
D. To serve multiple user groups with separate data using one codebase

Solution

  1. Step 1: Understand multi-tenant concept

    Multi-tenant apps use one codebase but keep data separate for each user group or tenant.
  2. Step 2: Identify Remix multi-tenant goal

    Remix apps handle requests to serve tenant-specific data without duplicating code.
  3. Final Answer:

    To serve multiple user groups with separate data using one codebase -> Option D
  4. Quick Check:

    Multi-tenant = shared code, separate data [OK]
Hint: Multi-tenant means one app, many separate user groups [OK]
Common Mistakes:
  • Thinking each tenant needs a separate app
  • Assuming tenants share the same data
  • Confusing multi-tenant with multi-instance
2. Which Remix loader function signature correctly receives the tenant info from the request?
easy
A. export async function loader({ request }) { /* use request to get tenant */ }
B. export async function loader(request) { /* tenant info here */ }
C. export async function loader(context) { /* tenant in context */ }
D. export async function loader() { /* no params for tenant */ }

Solution

  1. Step 1: Recall Remix loader signature

    Remix loaders receive an object with a request property: loader({ request }).
  2. Step 2: Identify correct usage for tenant extraction

    Tenant info is extracted from the request object, so the loader must accept { request }.
  3. Final Answer:

    export async function loader({ request }) { /* use request to get tenant */ } -> Option A
  4. Quick Check:

    Loader({ request }) is correct signature [OK]
Hint: Loader always gets an object with request property [OK]
Common Mistakes:
  • Using request as a direct parameter instead of inside an object
  • Expecting tenant info in a 'context' parameter
  • Defining loader with no parameters
3. Given this loader code snippet in a multi-tenant Remix app, what will be returned if the request URL is 'https://app.com/tenantA/dashboard'?
export async function loader({ request }) {
  const url = new URL(request.url);
  const tenant = url.pathname.split('/')[1];
  return { tenant };
}
medium
A. { tenant: 'tenantA' }
B. { tenant: 'dashboard' }
C. { tenant: '' }
D. Throws an error

Solution

  1. Step 1: Parse the URL pathname

    The pathname is '/tenantA/dashboard'. Splitting by '/' gives ['', 'tenantA', 'dashboard'].
  2. Step 2: Extract tenant from split array

    The tenant is at index 1, which is 'tenantA'.
  3. Final Answer:

    { tenant: 'tenantA' } -> Option A
  4. Quick Check:

    Split pathname[1] = tenant name [OK]
Hint: Split URL path by '/' and pick index 1 for tenant [OK]
Common Mistakes:
  • Picking index 2 instead of 1 for tenant
  • Not accounting for leading slash causing empty string at index 0
  • Assuming tenant is query parameter
4. Identify the bug in this Remix loader for multi-tenant data fetching:
export async function loader({ request }) {
  const url = new URL(request.url);
  const tenant = url.pathname.split('/')[2];
  if (!tenant) throw new Error('Tenant missing');
  return { tenant };
}
medium
A. Loader must not return an object
B. Tenant index should be 1, not 2
C. Error should be returned, not thrown
D. Missing await keyword before new URL()

Solution

  1. Step 1: Analyze pathname splitting

    Pathname split by '/' results in ['', tenant, ...]. Tenant is at index 1, not 2.
  2. Step 2: Understand error condition

    If tenant is at index 2, it will often be undefined, causing error even when tenant exists.
  3. Final Answer:

    Tenant index should be 1, not 2 -> Option B
  4. Quick Check:

    Tenant = pathname.split('/')[1] [OK]
Hint: Tenant is always at index 1 after splitting pathname [OK]
Common Mistakes:
  • Using wrong index for tenant extraction
  • Confusing async usage with URL constructor
  • Throwing error instead of handling gracefully
5. How can you ensure tenant data isolation in a Remix multi-tenant app when fetching data in the loader?
hard
A. Store tenant data in a global variable accessible to all requests
B. Fetch all tenants' data and filter on the client side
C. Use the tenant identifier from the request to query only that tenant's data
D. Use a single database table without tenant filtering

Solution

  1. Step 1: Understand tenant data isolation

    Each tenant must only access their own data to keep data private and secure.
  2. Step 2: Apply tenant filtering in loader

    Extract tenant ID from request and query database filtering by that tenant only.
  3. Final Answer:

    Use the tenant identifier from the request to query only that tenant's data -> Option C
  4. Quick Check:

    Filter data by tenant in loader for isolation [OK]
Hint: Filter data by tenant ID in loader, not client side [OK]
Common Mistakes:
  • Fetching all data and filtering later (inefficient and unsafe)
  • Using global variables for tenant data
  • Ignoring tenant filtering in queries
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard