
Build Your NFT Project in Minutes
How to use the ERC1155 monorepo template to launch your own NFT collection
The Challenge of Building NFT Projects
Building an NFT project from scratch involves tackling several complex components:
- Writing secure Solidity code
- Testing contract functionality
- Deploying to testnets and mainnet
- Verifying contracts on Etherscan
- Building a minting website
- Hosting NFT metadata securely
- Managing token images
- Connecting to wallets and contracts
What if you could skip most of this setup work and focus on creating your unique NFT collection? The ERC1155 Monorepo Template does exactly that by providing a fully-configured development environment with everything you need to launch your NFT project.
Template Architecture
1. Turborepo Monorepo Structure
The template uses Turborepo to organize a monorepo containing both the smart contract and frontend code:
. ├── apps/ │ └── frontend/ # Next.js frontend app ├── packages/ │ ├── api/ # tRPC API for metadata │ ├── auth/ # Authentication utilities │ ├── config/ # Shared config files │ ├── constants/ # Shared constants including contract addresses │ ├── contract/ # Solidity ERC1155 contract and tests │ └── db/ # Prisma schema and database utilities
This structure allows for a clean separation of concerns while sharing code between packages.
2. Smart Contract: ERC1155
The project includes a standards-compliant ERC1155 contract built with OpenZeppelin:
// From packages/contract/contracts/standard-erc1155.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
contract StandardERC1155 is ERC1155, Ownable, Pausable, ERC1155Supply {
// Contract name and symbol
string public name;
string public symbol;
constructor(
string memory _name,
string memory _symbol,
string memory _uri
) ERC1155(_uri) {
name = _name;
symbol = _symbol;
}
function setURI(string memory newuri) public onlyOwner {
_setURI(newuri);
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function mint(address account, uint256 id, uint256 amount, bytes memory data)
public
onlyOwner
{
_mint(account, id, amount, data);
}
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
public
onlyOwner
{
_mintBatch(to, ids, amounts, data);
}
// The following functions are overrides required by Solidity
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal override(ERC1155, ERC1155Supply) whenNotPaused {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
}
3. Metadata API
The frontend serves NFT metadata through a tRPC API, which marketplaces and wallets use to display your tokens:
// From packages/api/src/router/item.ts
export const itemRouter = createTRPCRouter({
byId: publicProcedure
.input(z.object({ id: z.number() }))
.query(async ({ input }) => {
// You can fetch from database or return static data
return {
id: input.id,
name: `NFT #${input.id}`,
description: "A unique collectible NFT",
image: `https://your-domain.com/images/${input.id}.png`,
attributes: [
{
trait_type: "Rarity",
value: "Legendary",
},
{
trait_type: "Type",
value: "Weapon",
},
],
};
}),
getAll: publicProcedure.query(async () => {
// Return all token metadata for your collection
// This could connect to a database via Prisma
return [/* token metadata array */];
}),
});
4. Next.js Frontend
The frontend provides a minting interface for your users and serves the metadata API:
// apps/frontend/src/app/api/item/[id]/route.ts
export async function GET(
req: Request,
{ params }: { params: { id: string } }
) {
// Parse the ID from the URL
const id = parseInt(params.id);
// Fetch metadata from tRPC
const caller = appRouter.createCaller({
prisma, // Prisma client instance
});
const metadata = await caller.item.byId({ id });
// Return formatted JSON for OpenSea/marketplaces
return NextResponse.json(metadata);
}
// apps/frontend/src/components/MintButton.tsx
"use client";
import { useState } from "react";
import { useContractWrite, usePrepareContractWrite } from "wagmi";
import { contractABI, contractAddress } from "@acme/constants";
export function MintButton({ tokenId }: { tokenId: number }) {
const [quantity, setQuantity] = useState(1);
const { config } = usePrepareContractWrite({
address: contractAddress,
abi: contractABI,
functionName: 'mint',
args: [tokenId, quantity],
});
const { write, isLoading, isSuccess } =
useContractWrite(config);
return (
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2">
<button
onClick={() => setQuantity(Math.max(1, quantity - 1))}
className="rounded-md border p-2"
>
-
</button>
<span className="w-8 text-center">{quantity}</span>
<button
onClick={() => setQuantity(quantity + 1)}
className="rounded-md border p-2"
>
+
</button>
</div>
<button
onClick={() => write?.()}
disabled={isLoading || !write}
className="rounded-md bg-primary px-4 py-2 text-white"
>
{isLoading ? "Minting..." : "Mint Now"}
</button>
</div>
);
}
Deployment Process
One of the best features of this template is how straightforward the deployment process is:
1. Deploy the Frontend
Simply connect your repository to Vercel and deploy with a few clicks. The template includes all necessary configuration for Vercel deployments.
# Get the URL after deployment
# e.g. https://your-project.vercel.app
2. Update the Contract URI
Use your Vercel domain in the deployment script to set the correct metadata URI base.
// packages/contract/scripts/deploy.ts
const uri = "https://your-project.vercel.app/api/item/{id}";
const nft = await NFT.deploy("MyNFT", "MNFT", uri);
3. Deploy the Contract
The template includes scripts for deploying to Goerli testnet or Ethereum mainnet.
# Deploy to Goerli testnet
turbo 1155:deploy:goerli
# Deploy to mainnet (when ready)
turbo 1155:deploy:mainnet
4. Verify the Contract
The deployment script provides the exact command for verifying your contract on Etherscan.
# Example verification command
npx hardhat verify --network goerli 0x123...ABC "MyNFT" "MNFT" "https://your-project.vercel.app/api/item/{id}"
Benefits of This Template
Rapid Development
Skip weeks of boilerplate setup and focus on your unique NFT collection features instead.
Secure Contracts
Built with OpenZeppelin's battle-tested contracts, reducing security risks in your NFT project.
Optimized Workflow
Turborepo configuration enables fast builds and efficient development across frontend and contracts.
Modern Tech Stack
Built with Next.js, TypeScript, tRPC, Prisma, and Hardhat for a scalable, maintainable codebase.
Customization Options
The template is designed to be easily customized for your specific NFT project:
- Metadata structure: Modify the tRPC router to return your custom attributes and traits
- Database integration: Connect to a database to dynamically serve metadata using the included Prisma setup
- Minting logic: Add custom minting rules, whitelist functionality, or reveal mechanics
- Frontend design: Customize the UI to match your brand and collection aesthetic
- Contract functions: Extend the contract with additional features like royalties or special minting mechanics
Get Started Today
The ERC1155 Monorepo Template offers a complete solution for NFT project development, allowing you to focus on creating unique assets and experiences rather than technical setup.
Check out the source code on GitHub and start building your NFT project today:
Key files and directories to examine:
- packages/contract/contracts/standard-erc1155.sol - The ERC1155 smart contract
- packages/api/src/router/item.ts - Metadata API implementation
- packages/constants/src/contract.ts - Contract addresses and ABIs
- packages/contract/scripts/deploy.ts - Contract deployment script
Pro tip: To see the template in action, visit the demo site where you can explore the frontend and metadata API endpoints.