Diagram showing the ERC1155 NFT template architecture with a Next.js frontend connected to a Hardhat smart contract project.

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:

Smart Contracts
  • Writing secure Solidity code
  • Testing contract functionality
  • Deploying to testnets and mainnet
  • Verifying contracts on Etherscan
Frontend & Metadata
  • 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:

Metadata API Route
// 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);
}
Minting Component
// 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

1

Rapid Development

Skip weeks of boilerplate setup and focus on your unique NFT collection features instead.

2

Secure Contracts

Built with OpenZeppelin's battle-tested contracts, reducing security risks in your NFT project.

3

Optimized Workflow

Turborepo configuration enables fast builds and efficient development across frontend and contracts.

4

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:

Pro tip: To see the template in action, visit the demo site where you can explore the frontend and metadata API endpoints.