Building Our School Blog with Next.js, Notion, GitHub, Vercel, and Squarespace
Welcome! In this tutorial, we’ll show how our STEAM and language school built a modern blog using an easy, affordable tech stack. The blog was created with Next.js 15 as the web framework, Notion as a CMS (content management system), Notion’s developer API to connect the content, GitHub for code version control, Vercel for deployment, and Squarespace for domain hosting. We’ll break down why we chose this stack and how we put everything together, step by step. The goal is to educate and inspire students, parents, and tech enthusiasts by demonstrating how approachable modern web development can be.
Introduction – Why This Stack?
Our school’s blog serves as a hub for educational articles, news, and student projects. We wanted a solution that teachers and even students could help manage, without needing deep web programming skills for every update. After some research, we chose the following tools for their accessibility, cost-effectiveness, and power:
- Next.js 15: A popular React framework for building fast websites. Next.js supports static site generation and server-side rendering, which means our blog pages load quickly and can be pre-generated for better performance. Version 15 is cutting-edge, supporting the latest React features and optimizations.
- Notion: An online workspace and note-taking app that doubles as a simple database. We use Notion as our CMS so that writing or editing a post feels as easy as editing a document. No complex admin panel needed – just a Notion page!
- Notion API: Notion provides a developer API that allows our website to fetch content from the Notion database. This is the bridge between the Next.js site and our Notion CMS.
- GitHub: A code hosting and version control platform. We keep our blog’s code in a GitHub repository so we can track changes and collaborate. It’s like Google Docs for code – every change is saved, and multiple developers (or tech-savvy students!) can work together.
- Vercel: A hosting and deployment platform that is actually created by the team behind Next.js. Vercel makes it super easy to deploy Next.js projects – we push our code to GitHub, and Vercel automatically builds and publishes the site. It’s fast and has a generous free plan, which is great for a school project.
- Squarespace (Domain Hosting): Our school’s main website domain was registered via Squarespace. Instead of buying a new domain, we used that existing sub-domain for the blog. Essentially, Squarespace acts as our domain registrar – we point the DNS to Vercel’s servers so that our blog can be accessed at our custom URL.
Why this stack? In short, it gave us a blog that’s easy to maintain, nearly free, and approachable for beginners. Notion is free for personal use (but we have a professional license already) and fits naturally into our daily workflow (our teachers were already familiar with it), and hosting the Next.js site on Vercel is also free – meaning the whole project incurred minimal cost. Now, let’s dive into how we built the blog step by step.
Step 1: Setting Up Notion as Our CMS
Our first step was to prepare Notion to manage our blog content. We treated Notion as a lightweight CMS where each blog post lives as a page in a Notion database. Here’s what we did:
-
Create a Blog Database in Notion: We made a new page in Notion and inserted a database (as a table) to hold our blog posts. We added useful fields (columns) to this table, such as Title (post title), Category (a short identifier for the content type), Status (a selection to indicate if a post is public or still in draft), Date (publication date), Author (post author name), and Tags (additional topics or categories). Each row in the table represents a blog post, and clicking a row opens the full post content (which we write in the Notion page).
[screenshot: Notion database setup] – In our Notion workspace, we have a “Blog Posts” table with columns for Title, Slug, Published, Date, etc., and each row is a post. This friendly interface lets our staff edit posts easily.
-
Get a Notion Integration Token: To allow our Next.js site to read from Notion, we created a Notion integration (essentially an API app) in our Notion account. Notion provided us with a secret token for this integration. We then shared our Blog database with this integration (so it has permission to read the content). The integration token is like a password that our website uses to securely access the Notion data. We stored this token in a configuration file (an environment variable) so that we don’t expose it in our code.
-
Add Some Sample Posts: To test things out, we added an example entry in the Notion database (How to use SkyViewer to Discover Asteroids) – we added a title, some content, and marked it as Published. Now we had content ready to be pulled into the site.
At this point, Notion is all set up. We have a token for API access and a database of posts. The beauty of this approach is that anyone on our team can add or edit posts in Notion’s friendly UI, and those changes will later show up on the blog site without touching any code.
Step 2: Building the Blog with Next.js 15
With content in place, we moved on to building the front-end of the blog using Next.js 15. Next.js allowed us to create a dynamic React website that could fetch data from Notion and generate pages for our posts. Here’s how we approached it:
- Initializing the Next.js Project: We used a Notion Blog template from Vercel's marketplace to kickstart our project. This gave us a pre-configured Next.js app with the Notion integration already set up, saving us time and effort. The template provided a basic structure with pages, components, and a development server ready to go. We chose Next.js because it's perfect for this use-case – it can pre-render pages (for speed) and easily fetch external data during the build process.
- Installing Dependencies: The Notion API came pre-installed in the template - we just needed to run npm iin our terminal to install all the necessary packages for the project.
- Connecting to Notion API in Code: With the Vercel template, we didn't need to set up the Notion connection from scratch. During the template setup process, Vercel prompted us for our Notion API credentials, which we added as environment variables. For local development testing, we created a .env.localfile with these same variables:
// .env.local NOTION_TOKEN=secret_abc123... DATABASE_ID=123456abcdef...
The template handled the Notion client initialization behind the scenes, creating the secure connection between our Next.js app and the Notion database using these environment variables.
-
Fetching the List of Posts: The template has a function (named notion.ts) to retrieve all blog posts from the Notion database that are marked “Published.” Using the Notion client, the code queries the database by its ID and filters for
Publishedposts: -
Generating Pages with Next.js: One of Next.js’s superpowers is Static Site Generation (SSG). We took advantage of that by using Next.js functions
getStaticPropsandgetStaticPathsto generate our blog pages. In simple terms, when we build the site, Next.js will run our code to fetch data (from Notion) and pre-build each page. For the homepage (blog index), we usedgetStaticPropsto fetch all published posts and pass them as props to the page component. For individual blog pages, we created a dynamic route[slug].jsand usedgetStaticPathsto let Next.js know all the post URLs to pre-render. Each[slug]page usesgetStaticPropsto fetch that post’s content from Notion by slug. -
Rendering Notion Content: Fetching a post’s content from Notion gives us a structured data format (Notion’s blocks). To display the post body on our site, we used a helper library called
notion-to-mdalong withreact-markdown. Essentially, we convert Notion blocks to Markdown text, then render that Markdown as HTML in our React component. This handles formatting like headings, paragraphs, images, etc., so the blog post looks as intended. For example, in ourgetSinglePostfunction we did something like:const mdBlocks = await n2m.pageToMarkdown(pageId); const mdString = n2m.toMarkdownString(mdBlocks);Then in the React page component, we render
mdStringusing<ReactMarkdown>to display the formatted post content. The details are a bit advanced, but the key point is that with a few library calls we turned Notion’s page data into a nicely formatted blog post on our site.
By the end of this development phase, we had a functioning Next.js application. We ran
Step 3: Version Control with GitHub (Automatically Created)
Since we launched our project from a Vercel template, we benefited from automatic GitHub integration. When we selected the template, Vercel created a GitHub repository for our project and configured it for version control without requiring manual setup. This seamless integration meant we didn't need to run separate
The GitHub repository serves as our project's central code storage, tracking all changes automatically. Every time we make updates through the Vercel platform, these changes are committed to GitHub, creating a comprehensive history of our development process.
This automatic version control provides significant benefits: we can track all modifications to the code, roll back to previous versions if needed, and collaborate efficiently without risk of overwriting each other's work. If someone needs to adjust the blog design or fix a component, these changes are automatically documented in GitHub.
(If you're not familiar with Git/GitHub: imagine a "Save As" history for your project, plus the ability for multiple people to work on it simultaneously. It's very handy for any coding project!)
Step 4: Deploying the Blog on Vercel
With code on GitHub, we were ready to deploy our blog so everyone (students, parents, the world!) could access it. Vercel made this process incredibly easy:
-
Automatic Build and Deploy: Once configured, we can make updates to our code using VS Code and any commits deploy automatically! Vercel pulls the latest code updates from GitHub and starts the build process. It installs our dependencies, runs the Next.js static generation (which fetched data from Notion), and then uploads the optimized output to their servers. In a matter of seconds, we get a live preview or deployed URL. The deployment log shows everything whether it went smoothly or not – no errors? our blog is live on the internet!

This screenshot shows the Vercel dashboard after a successful deployment. It displays the build logs and a message that our site is deployed, along with a preview URL. It’s a gratifying moment to see that green checkmark indicating our blog is live!
-
Production Deployment: Vercel gave us a default domain (something like
our-blog.vercel.app). We could share this link with everyone right away. Moreover, because we hooked up GitHub, any new commit to the main branch will trigger Vercel to rebuild and update the site automatically. For real-time content updates, we implemented Notion's webhook system with a custom API that triggers Vercel deployments whenever content changes in Notion. For example, when a teacher adds a new post in Notion, our webhook automatically triggers a re-deploy, and the content goes live without manual intervention. This fully automated continuous deployment system keeps our blog constantly in sync with our content!
At this stage, our Next.js blog powered by Notion was officially live on the web, hosted by Vercel. The performance was great, and we had zero servers to manage – Vercel handled all the scaling and delivery. Our instructors found it amazing that a full website could go live so quickly.
Step 5: Connecting Our Custom Domain (Squarespace)
While our blog was live on a Vercel URL, we preferred to use our school’s own domain for consistency and professionalism. Our domain was managed through Squarespace (since our main website was built there earlier). Here’s how we pointed the domain to our new Vercel site:
- Add Domain in Vercel: In the Vercel dashboard for our project, we went to the Domains section and added our custom domain (e.g., blog.ourschool.comor if replacing the main site,ourschool.com). Vercel then knows to accept requests for that domain and serve our project.
- Update DNS Records on Squarespace: This is the only part that involves a bit of technical configuration, but it’s a one-time setup. We opened our Squarespace domain settings and found the DNS configuration panel. Following Vercel’s instructions, we added a few DNS records: specifically, an A record (pointing the root of our domain to Vercel’s server IP address) and a CNAME record (for the www.subdomain pointing to Vercel) as provided by Vercel. Essentially, these records tell the internet, “hey, our domain’s website is hosted over at Vercel now.” Squarespace, being our domain host, allows custom DNS, so this was straightforward. We saved the changes.
- Propagation and HTTPS: After updating DNS, we waited a short while (DNS changes can take a few minutes to hours to propagate worldwide). Vercel automatically provisioned an SSL certificate for our domain, so the site would be secure (https://) once active. In no time, our blog was accessible at our own familiar URL. For example, visitingblog.ourschool.comwould show the Next.js blog content, even though the code is hosted on Vercel – the domain masking is seamless.
Now our school’s blog had a custom address that parents and students could easily remember. We essentially “plugged” a modern app into a domain we owned, demonstrating how different services (Squarespace and Vercel in this case) can work together.
Summary – What We Learned and Why It Matters
By combining these tools, we built a modern, professional blog without a large development team or budget. Let’s recap the tech and the takeaways:
- Next.js 15 gave us a powerful yet developer-friendly framework to build the site. It handled the heavy lifting of optimization and page generation, which means even with modest coding, we achieved a fast and SEO-friendly website. Students learned about React and Next.js fundamentals through this project, seeing how frameworks simplify development.
- Notion as a CMS proved to be a brilliant choice for ease of use. Our educators can write and edit posts in an interface they find comfortable (no code, no complex forms – just a Notion page). This lowers the barrier for contributing content. From a learning perspective, it shows that content creation and management doesn’t always require specialized CMS software – sometimes a tool you already use (like Notion) can wear a “CMS hat” with a little integration work.
- Notion API integration taught us about how different services can communicate. By obtaining a secret token and using Notion’s API, we pulled data securely into our site. This was a real example of backend integration – an advanced concept made accessible. For our students interested in programming, it was eye-opening to see how an API works in practice (requests and responses of data).
- GitHub demonstrated the importance of version control and collaboration. Every change to the code is tracked. This instilled good practices like committing changes with messages, and it showed how developers around the world collaborate on projects. Parents and students can view the repository to trace the project’s evolution, highlighting transparency in development.
- Vercel showcased how deployment and hosting have become incredibly user-friendly. We didn’t have to set up or manage a server. We saw that by leveraging a platform like Vercel, anyone can deploy a web app in a few clicks – it’s practically made for hobby projects, startups, and educational purposes. This demystified the process of “putting a site online” for everyone involved.
- Squarespace (Domains) reminded us that even if you use different platforms, you can integrate them. We kept our existing domain and simply pointed it to the new site, preserving our online identity. This shows a practical skill: configuring DNS and domains, which is valuable knowledge for students interested in IT and web technologies.
What can students and parents learn from this? Most of all, we hope it’s inspiring to see that modern web development is approachable and modular. You don’t need to build everything from scratch – you can assemble solutions using best-in-class services. Our project was essentially “gluing together” excellent tools: a bit of coding here, a bit of service configuration there. This modular approach means a small team (or a motivated student!) can create something impressive in a short time.
For students, this project is a blueprint of how to turn ideas into reality using technology. It blends creativity (writing blog content, designing a site) with programming and problem-solving. It also emphasizes planning and choosing the right tools for the job – an important engineering lesson.
For parents, it’s a glimpse into how software development has evolved. The skills their kids learn (like using APIs, understanding cloud platforms, coding with frameworks) empower them to build real applications quickly. It’s a far cry from the early days of the web – it’s much more accessible now.
In the end, our STEAM and language school’s blog is more than just a website. It’s a learning project that demonstrates collaboration between content creators and developers, and it highlights how technology can serve community and educational goals. We built something useful for our readers, and along the way, everyone involved gained knowledge. We hope this story encourages you to experiment with modern web tools – if a group of students and teachers can do it, so can you!
Happy coding and publishing! 🚀
References: The implementation drew inspiration from various resources on Next.js and Notion. For instance, Next.js’s official docs on static generation and community tutorials on using Notion as a CMS were valuable. We also referred to Vercel’s guides for deploying with GitHub and setting up domains. These sources underline how a Notion-backed Next.js blog can be created and deployed with ease. The result is a fast, free (or low-cost) site that anyone in our school can contribute to, embodying the spirit of accessible modern web development.
