Open-source project
Lrunlin/blog avatar
Lrunlin/blog

Lrunlin/blog: a full-stack blog community built on Next.js and Koa

使用Next.js+React.js+Koa+Typescript搭建的技术博客社区

800 stars129 forksTypeScriptApache-2.0

At a glance

What is it?
This repository is a complete blog community system, with a Next.js front end, a Koa2 back end over Sequelize and MySQL, Redis for sessions and caching, and an Ant Design and Tailwind interface. It is a graduation-project-grade application that includes posts, comments, likes, follows, favourites, a question and answer feature, a message system, themes and an admin console, and it was migrated from the pages router to the app router in 2024.
Who is it for?
This repository suits a student or developer who wants a working multi-user blog community to read, run and extend, since the feature list is broad enough to be instructive and the code is TypeScript throughout. It is the wrong base for a production blog that needs a maintained upstream, because the README documents manual steps such as clicking install.bat and the project is aimed at course and graduation-project use.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 53 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project is and what the stack is

The repository is a technical blog community system, and the README is written in Chinese, so the description here follows its structure rather than translating every line.

The stack is laid out explicitly. The front end is Next.js, on React 19 with the app router, and the server side is Koa2 with Sequelize as the ORM. The databases are MySQL and Redis. The development language is TypeScript, the component library is Ant Design, the CSS approach is Tailwind CSS, and React state management is Zustand. Object storage supports Alibaba Cloud and Qiniu.

That is a coherent and modern choice of stack, and the part worth noting is the split of state. MySQL holds the durable relational data, and Redis holds sessions and whatever is cached, which is what lets the same codebase run a write-heavy workload and a read-heavy one.

The README also mentions that the system is relatively complete and handles the SEO a blog site needs, so it can be used in production, and that it can serve as a graduation project. There are two associated papers, a user-side CSR version with a Vue 3 front end and a Node.js and TypeScript server, and a separate Next.js plus Vue 3 plus Express personal blog repository, both with papers attached.

The licence field on the repository records Apache-2.0, the primary language is TypeScript, and the last push was on 2026-09-02.

The pages router to app router migration

The first thing the README explains is a change, and it is the kind of change that matters if you are picking this repository up to learn from it or to reuse the code.

The note is dated 2024/06 and says the front end moved from the pages router to the app router. If you want the pages router version, the README points at a specific commit, the last one before the switch, and a link to that commit on GitHub.

bash
git clone https://github.com/Lrunlin/blog.git
bash
git checkout 9d837612d2bbc50b80248ec06b8af04f9c5ecf01

So the choice is explicit and cheap. You clone the repository and either work with the current app router code or check out that commit for the older pages router structure.

This is worth understanding before reading any of the client code, because the two routers are not variants of each other. The pages router is file system based with a pages/ directory and the getServerSideProps style data fetching, and the app router is layout and server component based with a different data model and a different caching behaviour. Code, structure and idioms differ throughout, and the presence of both in the history means the repository contains two generations of frontend work rather than one.

The repository layout reflects the split into client and server: the top level has a client/ directory, a server/ directory, a blog.sql file with the database schema, and three Windows batch files, dev.bat, install.bat and lint.bat.

Session and JWT authentication, and why the README recommends one

The authentication section is short and gives a reason rather than just an option.

The system supports both JWT and Session authentication, and the explanation is that the system has an account deletion feature, and since JWT is stateless the recommendation is to use Session stored in Redis.

That is a good reason and it connects the two decisions. A stateless token cannot be revoked before it expires, so a user who asks for their account to be deleted has left a valid credential behind. A session in Redis can be deleted at the same moment the account is. The cost of a session is the extra lookup on every request and the shared state, and for an application that needs revocation, that is a trade worth making.

The pairing of Session with Redis is the other half. Storing sessions in a database is workable but adds load to the primary datastore, and Redis is already in the stack.

So the authentication design is a two-axis decision rather than a single one, and the README's recommendation follows from the account deletion requirement. A team that has no deletion requirement, or that runs a stateless API behind a gateway, could reasonably use JWT and skip the session store.

The user-facing feature list

The user-side feature list is what makes this a community system rather than a personal blog.

Accounts cover login, registration and logout, with email registration and GitHub login, and the GitHub path is login only. Around the accounts sit the social features: following authors, favourites folders, favouriting articles, and list queries for both, plus settings for user information and display of the author's social accounts.

Content covers article creation, editing, deletion and lookup, with a drafts box, and the homepage does article recommendations. Interaction covers comments and likes, and there is a question and answer feature where a user asks a question, an answer is accepted, and other users answer.

There is a site message system with notification settings for articles and comments, a leaderboard of articles by publication count and by followers, and article page themes where a user can apply to create and use one.

The theme feature is unusual and worth a second look. A theme per article page, with an application process, is a way of letting a reader set typography and layout for long-form reading, and having it go through an application means the platform can moderate what a theme does to a page that carries other people's content.

The admin console, including the crawler

The management system list is where the project shows its full feature set, and it is broader than a typical blog admin.

Basic content administration is there, with paginated article queries, the ability to look up a specific article and edit or delete it, article type management, and comment management including deleting user messages. Publishing handles image upload with watermarking and compression applied to the images.

Then there are several features that belong to a content platform rather than a blog. A crawler system that automatically grabs articles from two Chinese developer communities, Sifou and Juejin. Data processing for promotional content. A homepage message notification feature. A large screen data visualisation that shows simple information about the current server state. Handling of external links, of friend links, and of images inside the object storage.

The crawler deserves a note, because it is a decision rather than a feature. Pulling articles from other sites into your own archive is how a community site fills up quickly, and it is also how a site ends up republishing content it does not have the rights to. The README lists it without comment, so the licensing question is left to the operator.

The large screen server information view is the other unusual one, and it points at the fact that this is a deployment that the author runs, with the server metrics surfaced as a large screen display in the admin area.

Running it, and the Windows-shaped setup

The startup instructions are Windows-first, and that is the first thing to know before you try them.

The environment requirements are Node.js 20 or newer, MySQL 8.x and Redis. The steps are: import the SQL file, install yarn globally with npm install yarn -g if you do not have it, click install.bat to install the dependencies, close the command window when it finishes, and then click dev.bat to start the project.

bash
npm install yarn -g

The batch file approach means the setup is not reproducible in the way a package.json script would be, and it means the project is awkward to run on a machine that does not have Windows. The README does say the production deployment uses a Linux panel called Baota, so the target environment is Linux even though the development convenience is Windows.

There is a specific troubleshooting note about the sharp plugin. If the sharp installation fails, the advice is to use a proxy to retry the install or consult the sharp documentation's Chinese mirror. sharp is the image processing library, and it ships platform-specific prebuilt binaries, which is why its install is the one that fails on a given machine.

The environment variables are handled by renaming template files. The client folder has its env folder with an .env.production file to be filled in following .env.development, and the server folder has its env folder where the template file is renamed to the environment name, development or production, and then filled in.

The repository root confirms the shape: a client/ directory, a server/ directory, blog.sql, and the dev.bat, install.bat and lint.bat scripts.

Production deployment with pm2 and socket.io

The production notes are where the operational reality of this stack shows up.

The site is deployed with Baota, a Linux server control panel, and the README acknowledges that server environments differ between developers and offers contact details for deployment problems.

The specific deployment detail that will bite someone new is the pm2 and socket.io interaction. The project uses both pm2 and socket.io, and pm2 has to be replaced with the globally installed @socket.io/pm2 package, with the installation described in install.bat. The README points at the socket.io documentation on this and says that if the service fails to start in production, check the @socket.io/pm2 installation.

That is a well-known gotcha with socket.io under pm2, where the cluster mode needs the socket.io-aware pm2 fork to share the port between workers. Getting it wrong produces a port already in use error that looks like a configuration problem rather than a process manager problem.

The README also repeats the sharp troubleshooting note for production, this time suggesting checking the Node.js version or excluding the need for a linux-specific sharp build, which is what happens when a Windows-built native module reaches a Linux server.

The recommended server list is specific to Chinese providers, with Tencent Cloud and Alibaba Cloud lightweight application servers, and Qiniu for CDN and object storage, which matches the object storage support in the stack.

Where this project is the wrong choice

The first limitation is the setup is not scriptable in the usual sense. The install path is a batch file that you click, and the environment configuration is a matter of renaming template files by hand. That is fine for the author's own machine and poor for a team, for CI, or for a container image, where the same steps have to be expressed as commands that a script can run.

The second is the scope relative to the maintenance burden. There is an admin console, a crawler, a Q and A feature, a message system, theming, an object storage pipeline with image watermarking and compression, and a server metrics screen. Each of those is a feature that has to be secured, updated and kept working. A blog needs a small fraction of that, and the rest is surface area.

The third is the crawler, which is both a legal and a technical liability. Automatically pulling articles from other communities means your archive contains content whose licence you do not control, and it means your site is dependent on the HTML of sites you do not control.

The fourth is the platform assumptions. The dev workflow is Windows batch files, the deployment panel is a Chinese Linux control panel, the object storage integrations are for Alibaba Cloud and Qiniu, and the OSS handling is built around that. A team outside that ecosystem will find several pieces to replace.

The fifth is the project status. The last push was on 2026-09-02, the repository has no GitHub releases, and the README's framing is that of a personal project and a graduation project. There is no upstream to pull fixes from, so any security issue found in the dependencies or in the code itself is yours to fix.

How it compares with a static blog generator and with a hosted community platform

The comparison with a static site generator is the first one, and the difference in approach is where the code runs. A generator such as the Next.js static export or a dedicated static site generator produces files at build time and serves them from a CDN, which needs no application server, no database and no session store. This system runs a Koa server, a MySQL database and a Redis instance, and it has an admin console where an editor publishes and where comments are moderated. A static site gives you none of that, and it also gives you no way to have comments at all.

So the question is whether you need the dynamic parts. A personal blog with a feed and tags does not need them, and a static site will be faster, cheaper and more robust for that case. A community with accounts, comments, follows, private messages and a Q and A section does need them, and this repository is one of the more complete implementations of that shape that you can read in TypeScript.

The second comparison is with a hosted community platform, such as a Discourse or a Chinese equivalent. The difference is ownership. A hosted platform gives you a moderation workflow, a spam filter, a plugin system, an admin team and someone answering when the server breaks, and this repository gives you the code and nothing else. For a site that needs to moderate comments from strangers, a hosted platform's tooling is a serious advantage over a hand-built admin console.

The third comparison is with the other versions the README lists, the Vue 3 client-side rendering version and the separate personal blog repository with Next.js, Vue 3 and Express. Those are useful precisely because they show the same product built differently, with a different front end framework and a different server framework. If your interest is in comparing front end approaches on the same backend design, that is the most interesting thing in the README.

The fourth point is about intent. The README says the system can be developed into other projects, used as a graduation project or a thesis, and that there are papers attached to the versions. That framing means the code is a teaching artifact first, and reading it as such is the right expectation.

Licence, provenance and what to check before running it

The licence field on the repository says Apache-2.0, and the LICENSE file is at the root. A permissive licence with a patent grant means you can read the code, run it, change it and put it into a project, and the README separately invites contact for other projects, graduation projects and thesis work, which suggests the author is open to reuse with attribution.

The primary language is TypeScript and the topic tags name the stack: blog, koa, mysql, nextjs, nodejs, react and typescript. The README links a live preview at blogweb.cn, the GitHub repository as the main repository, and a Gitee repository that is explicitly a sync mirror with no other operations, which is a common pattern for projects whose audience is in China.

Four things to check before you run it.

That you can fill in the environment files. The client and server configuration comes from renaming templates, and the values you will need include the MySQL and Redis connection details and the object storage credentials, and the README does not enumerate them beyond the procedure.

That you have imported blog.sql, since the schema is shipped as a file rather than as migrations, which means you get the initial state but not the upgrade path.

That the sharp native module matches your platform, since it is the dependency most likely to fail on install and the README calls it out twice.

And that you have read the authentication section and chosen deliberately between JWT and Session, because the README's recommendation of Session in Redis exists because of the account deletion feature, and a deployment that keeps a JWT issued to a deleted account has a problem the author already solved.

Editorial conclusion

This repository suits a student or developer who wants a working multi-user blog community to read, run and extend, since the feature list is broad enough to be instructive and the code is TypeScript throughout. It is the wrong base for a production blog that needs a maintained upstream, because the README documents manual steps such as clicking install.bat and the project is aimed at course and graduation-project use. Before running it, read the environment variable section, because the client and server configurations are filled in by renaming template files, and expect the setup to be Windows-shaped given the batch files, even though the deployment path described is a Linux panel.

Frequently asked questions

What is the Lrunlin/blog project?

It is a technical blog community system built with Next.js and React 19 on the front end and Koa2 with Sequelize on the server, using MySQL and Redis for data and sessions. It includes posts, comments, likes, follows, favourites, a question and answer feature, site messages, per-article themes and a management console.

What changed in the Lrunlin/blog repository in 2024?

The front end moved from the pages router to the app router. The README points at the last pages router commit, 9d837612d2bbc50b80248ec06b8af04f9c5ecf01, which you can check out after cloning if you want the older structure.

Does Lrunlin/blog support both JWT and Session authentication?

Yes, it supports both. The README recommends Session stored in Redis, because the system has an account deletion feature and JWT is stateless, so a token issued to a deleted account cannot be revoked.

What do I need to run Lrunlin/blog locally?

Node.js 20 or newer, MySQL 8.x and Redis. You import the blog.sql file, install yarn globally, run install.bat to install dependencies, then dev.bat to start the project. The environment variables come from the template files in the client and server env folders.

What does the Lrunlin/blog management console include?

Paginated article queries, editing and deleting articles, article type management, comment and user message management, image upload with watermarking and compression, a crawler that automatically grabs articles from Sifou and Juejin, promotional content data processing, homepage notifications, object storage image handling, external link and friend link handling, and a large screen view of server information.

What licence is Lrunlin/blog released under?

Apache-2.0, with the terms in the LICENSE file at the root of the repository. The README also invites contact about using the system for other projects, graduation projects and thesis work.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Lrunlin/blog on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lrunlin-blog.svg)](https://hysenlabs.com/projects/lrunlin-blog)

Was this useful?