Project Structure
Understanding how a BlocksWeb project is organized will help you navigate your codebase and know where to place different types of files.
Standard Project Structure
Here's what a typical BlocksWeb project looks like:
my-blocksweb-project/
├── app/ # Next.js App Router (or pages/)
│ ├── [[...path]]/ # Catch-all route for BlocksWeb pages
│ │ └── page.tsx # Main page component
│ ├── layout.tsx # Root layout
│ └── globals.css # Global styles
├── components/ # Your BlocksWeb components
│ ├── Hero.tsx
│ ├── FeatureCard.tsx
│ ├── BlogPost.tsx
│ └── ProductGrid.tsx
├── public/ # Static assets
│ ├── images/
│ ├── favicon.ico
│ └── robots.txt
├── lib/ # Utility functions
│ ├── utils.ts
│ └── api.ts
├── types/ # TypeScript type definitions
│ └── index.ts
├── blocksweb.config.ts # BlocksWeb configuration
├── next.config.js # Next.js configuration
├── tailwind.config.js # Tailwind configuration (if using)
├── tsconfig.json # TypeScript configuration
├── .env.local # Environment variables (not committed)
├── .gitignore
├── package.json
└── README.mdKey Files and Folders
blocksweb.config.ts
The main BlocksWeb configuration file. This is where you:
- Register components
- Define collections
- Configure settings
- Add scripts and styles
import { IBlockswebComponent } from '@blocksweb/core';
import Hero from './components/Hero';
import FeatureCard from './components/FeatureCard';
export const editorComponents: IBlockswebComponent[] = [
Hero,
FeatureCard,
];
export const collections = [
// Define your collections here
];
export const settings = {
editorComponents,
collections,
scripts: ['https://cdn.tailwindcss.com'],
styles: ['/custom-styles.css'],
};app/[[...path]]/page.tsx (App Router)
The catch-all route that renders BlocksWeb pages:
import { BlockswebProvider, Canvas } from '@blocksweb/core/client';
import { settings } from '@/blocksweb.config';
export default function Page({ params }: { params: { path?: string[] } }) {
const path = params.path ? '/' + params.path.join('/') : '/';
return (
<BlockswebProvider settings={settings}>
<Canvas path={path} />
</BlockswebProvider>
);
}components/ Directory
Store all your BlocksWeb components here. Organize them by category if needed:
components/
├── marketing/
│ ├── Hero.tsx
│ ├── CallToAction.tsx
│ └── Testimonials.tsx
├── content/
│ ├── RichContent.tsx
│ ├── ImageGallery.tsx
│ └── VideoEmbed.tsx
├── layout/
│ ├── Header.tsx
│ ├── Footer.tsx
│ └── Container.tsx
└── ecommerce/
├── ProductCard.tsx
├── ProductGrid.tsx
└── AddToCart.tsx.env.local
Environment variables for development. Never commit this file!
# BlocksWeb Configuration
BLOCKSWEB_API_KEY=bw_live_...
BLOCKSWEB_WORKSPACE_ID=ws_...
# Optional: Self-hosted API
BLOCKSWEB_API_URL=https://api.yoursite.com
# Optional: Feature flags
BLOCKSWEB_ENABLE_ANALYTICS=true
BLOCKSWEB_ENABLE_AB_TESTING=truelib/ Directory
Utility functions and helpers:
// lib/utils.ts
export function formatDate(date: Date): string {
return new Intl.DateTimeFormat('en-US').format(date);
}
export function cn(...classes: string[]): string {
return classes.filter(Boolean).join(' ');
}types/ Directory
Shared TypeScript types:
// types/index.ts
export type Product = {
id: string;
name: string;
price: number;
image: string;
description: string;
};
export type BlogPost = {
id: string;
title: string;
author: string;
date: Date;
content: string;
slug: string;
};App Router vs Pages Router
BlocksWeb supports both Next.js routing systems.
App Router Structure (Recommended)
app/
├── [[...path]]/
│ └── page.tsx # BlocksWeb pages
├── api/
│ └── custom-endpoint/
│ └── route.ts # API routes
├── layout.tsx # Root layout
├── not-found.tsx # 404 page
└── globals.cssPages Router Structure
pages/
├── [[...path]].tsx # BlocksWeb pages
├── api/
│ └── custom-endpoint.ts # API routes
├── _app.tsx # App wrapper
├── _document.tsx # Document
└── 404.tsx # 404 page
styles/
└── globals.cssAdvanced Organization
For larger projects, consider this structure:
my-blocksweb-project/
├── apps/ # Monorepo apps (optional)
│ └── web/
├── packages/ # Shared packages (optional)
│ └── ui/
├── src/
│ ├── components/
│ │ ├── blocksweb/ # BlocksWeb components
│ │ │ ├── marketing/
│ │ │ ├── content/
│ │ │ └── ecommerce/
│ │ └── ui/ # Regular UI components
│ │ ├── Button.tsx
│ │ └── Card.tsx
│ ├── lib/
│ │ ├── blocksweb/
│ │ │ ├── collections/ # Collection definitions
│ │ │ └── providers/ # Custom providers
│ │ └── utils/
│ ├── hooks/ # Custom React hooks
│ │ ├── useProducts.ts
│ │ └── useBlogPosts.ts
│ ├── types/
│ └── config/
│ └── blocksweb.config.ts
├── public/
├── .env.local
└── package.jsonComponent File Structure
Each component file should follow this pattern:
// 1. Imports
import { IBlockswebComponent } from '@blocksweb/core';
import { RichText, Image } from '@blocksweb/core/client';
// 2. Type definitions
type MyComponentProps = {
title: string;
description: string;
};
// 3. Component implementation
const MyComponent: IBlockswebComponent<MyComponentProps> = ({
title,
description
}) => {
return (
<div>
<h2>{title}</h2>
<p>{description}</p>
</div>
);
};
// 4. Schema definition
MyComponent.schema = {
displayName: 'My Component',
category: 'Content',
options: [
{ type: 'text', name: 'title', label: 'Title', default: '' },
{ type: 'text', name: 'description', label: 'Description', default: '' },
],
};
// 5. Export
export default MyComponent;Environment Files
Use different environment files for different stages:
.env.local # Local development (not committed)
.env.development # Development defaults (can be committed)
.env.production # Production values (not committed)
.env.example # Example file (committed)Example .env.example:
# BlocksWeb Configuration
BLOCKSWEB_API_KEY=your_key_here
BLOCKSWEB_WORKSPACE_ID=your_workspace_id_here
# Optional Configuration
BLOCKSWEB_API_URL=https://cloud.blocksweb.nl
BLOCKSWEB_ENABLE_ANALYTICS=truegitignore
Make sure your .gitignore includes:
# dependencies
node_modules/
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.production.local
.env.development.local
.env.test.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.tsPackage.json Scripts
Useful scripts for your package.json:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"type-check": "tsc --noEmit",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"clean": "rm -rf .next node_modules"
}
}Collections Organization
If using collections, organize them in a dedicated folder:
lib/blocksweb/collections/
├── index.ts # Export all collections
├── products.ts # Product collection
├── blogPosts.ts # Blog post collection
└── providers/ # Custom providers
├── productProvider.ts
└── blogProvider.tsExample collections/index.ts:
import { products } from './products';
import { blogPosts } from './blogPosts';
export const collections = [products, blogPosts];Best Practices
1. Consistent Naming
// Component files: PascalCase
Hero.tsx
FeatureCard.tsx
ProductGrid.tsx
// Utility files: camelCase
formatDate.ts
fetchProducts.ts
validateInput.ts
// Type files: PascalCase types
types/Product.ts
types/BlogPost.ts2. One Component Per File
// Good
components/Hero.tsx
components/FeatureCard.tsx
// Avoid
components/AllComponents.tsx // ❌ Multiple components in one file3. Colocate Related Files
components/Hero/
├── Hero.tsx
├── Hero.test.tsx
├── Hero.stories.tsx
└── Hero.module.css4. Use Index Files for Clean Imports
// components/index.ts
export { default as Hero } from './Hero';
export { default as FeatureCard } from './FeatureCard';
export { default as ProductGrid } from './ProductGrid';
// Then import like this:
import { Hero, FeatureCard } from '@/components';Monorepo Structure (Advanced)
For large organizations, use a monorepo:
my-blocksweb-monorepo/
├── apps/
│ ├── website/ # Main website
│ ├── blog/ # Separate blog app
│ └── admin/ # Admin dashboard
├── packages/
│ ├── blocksweb-components/ # Shared BlocksWeb components
│ ├── ui/ # Shared UI components
│ ├── types/ # Shared types
│ └── utils/ # Shared utilities
├── package.json # Root package.json
├── turbo.json # Turborepo config
└── pnpm-workspace.yaml # PNPM workspace configNext Steps
Now that you understand the project structure:
- Components & Schema - Deep dive into component architecture
- Options System - Learn all option types
- Creating Components - Best practices for building components