Okay, I have to be honest with you from minute one. This project is costing me quite a bit more than I thought. Hytale has already been released, people are playing, creating mods, uploading content… and my website is still upside down.
I’m going to tell you something I don’t usually tell. I’m quite demotivated. Last week I tried to do a little promotion on Reddit, to see if the idea had traction, if people were interested… and my post was deleted. Twice. In two different subreddits. They didn’t even let me validate the idea. And I understand it, the market is absolutely saturated. There are mod websites popping up like mushrooms, everyone wants to be the next CurseForge of Hytale. But I’m excited to get this done, so here we are. Second chapter. Let’s get to it.
The Project and Why I Make It Public
For those who are new to this series, I’ll put you in context quickly. I am creating from scratch a website for the Hytale community. Not just any website, but a platform where creators can upload their mods, texture packs, maps, tools… everything you can think of related to Hytale and on top of that earn money depending on the traffic they generate. If you’ve played Minecraft, it’s like a CurseForge or a Planet Minecraft (some very old ones will remember Planet Minecraft). Well that, but for Hytale.
And I’m documenting everything here. Why? Well, because I think there is very little content of people showing the REAL process of creating a project. Not the pretty final result, no. The guts. The mistakes. The technical decisions. The frustrations. Everything. I hope it serves as inspiration and that you learn with me on this path. Because I am also learning, this is not a tutorial where I already know everything. It’s a “let’s see how this turns out”.
What We Are Going to See Today
Having said that, what’s up today? Well today we stop painting monkeys on the frontend and get into the mud for real. In the previous chapter we fought with the whole design issue… Today it’s time to build the foundations.
I’m going to explain how I designed and set up the database with Prisma DB. And not just “I used Prisma”, no. I’m going to show you the whole model, why I made each decision and how this works inside. I have also integrated custom logins with Google, Discord and even login by email, so that no one has to remember another password. I put captcha because if I don’t put it, the day I launch this the bots are going to burst me. And finally, automatic database backups, which is super important and many people ignore it.
The Database with Prisma
We start with the heart of any application: the database. And here I have made a decision that I want to explain well to you. I have decided to use Prisma DB. What is Prisma? Well, Prisma is what is called an ORM, an Object-Relational Mapping. But don’t worry, I’m not going to give you the theoretical speech. Basically, Prisma is a tool that makes our lives incredibly easier when working with databases from JavaScript or TypeScript.
Why do I say it makes life easier? Well, because instead of writing SQL by hand, which you already know how fun that is… you define your model in a super simple language, execute a command, and Prisma takes care of creating the tables, the relationships, the TypeScript types… everything. Magic.
Why Prisma and Not Another ORM
You will ask why Prisma and not Sequelize, TypeORM, or Drizzle which is so fashionable. Well look, I’ll give you my reasons. First: the integration with Next.js is brutal. Since I’m using Next.js for the project, Prisma fits like a glove. You don’t have to do tricks to make it work. Second: the schema language is super readable. Now I’ll show it to you and you’ll see that even your grandmother could understand more or less what each thing does. Third: automatic TypeScript types. This is gold. Every time you change the model, Prisma regenerates the types and your editor warns you if you are doing something wrong. Goodbye to stupid “this field does not exist” bugs. And fourth: Prisma Studio. It has a graphical interface included to view and edit data. Not that I use it much, but for debugging it comes in handy.
The Database Model
I’m going to tell you the interesting part. My database model turned out quite large, chunkier than I initially expected. But I’ll explain it broadly because I want you to understand the logic.
The key to all this design is the Content table. I have decided to create a generic content table. Why? Because if you think about what the web is going to have… we have mods, maps, texture packs, tools, servers… There are many different types of content. The initial temptation is to create a table for each one: Mods table, Maps table, Textures table… But that is hell to maintain. Every time you want to add a common field, you have to touch it in five places. Every time you want to add a new type, you have to create a new table, new migrations…
So, what have I done? I have created a parent table called Content that has all the common fields: title, description, author, creation date, number of downloads, rating… And then it has a type field that indicates if it is a mod, a map, a texture or whatever.
And from this Content table hang the child tables. For example, ContentVersion. Because of course, a mod doesn’t have a single version. A mod can have version 1.0, 1.1, 2.0… And each version can be compatible with different versions of Hytale. So I have a versions table that is related to the parent content.
Then I have ContentFile, which are the downloadable files for each version. Because a version can have several files: the mod itself, a readme, a configuration file… I have ContentImage for screenshots and previews. I have ContentTag for tags and categories. And I have ContentRating for user ratings.
Relationships Between Tables
And here comes the interesting part, relationships. A Content belongs to a User, who is the creator. A User can have many Content. That is a classic one-to-many relationship. But then I have more complex things. For example, favorites. A user can mark many contents as favorites, and a content can be a favorite of many users. That is a many-to-many relationship, and Prisma manages it super well with an intermediate table. The same with followers. A user can follow other users. That is a reflexive many-to-many relationship, that is, from the User table with itself. It sounds messy but in Prisma it’s four lines.
The Workflow with Prisma
And this is the beauty of Prisma. Imagine I want to add a new field. For example, I want contents to have a “license” field to indicate if it is Creative Commons, MIT, whatever. Well, I simply go to the Content model, add license String? (the question mark means it’s optional), and in the terminal I execute:
npx prisma db push
And that’s it. Prisma compares the schema with the database, sees that there is a new field, and adds it. Without writing SQL, without creating migrations by hand, without headaches. And automatically, the Prisma client in my code already has the updated type. If I try to access content.license, TypeScript already knows it exists and that it is an optional string. Brutal.
Authentication with Social Logins
Next topic: users and authentication. And here I want to be clear about something. Honestly, I hate registering on new websites. Really. Every time I see a registration form with email and password, I get brutally lazy. Another password to remember? Another confirmation email? No, thanks. So, if I hate it, why am I going to force my users to do it? It makes no sense.
That is why I have implemented what are called “authentication providers”. Basically, instead of creating their own account, the user can login with an account they already have: Google, Discord, or if they really want, email.
Why These Three Providers
We have “Continue with Google”, “Continue with Discord”, “Continue with Email”. Why these three? Google because everyone has a Google account. It’s the standard. Discord because the Hytale community is very involved in Discord. There are Hytale Discord servers with thousands of users. It makes sense that they can use that account. Email as a fallback for the four crazy people who don’t want to use any of the other options. But it’s not the typical email with password, it’s a “magic link”. They receive an email with a link, click, and they are in. No passwords.
Implementation with Auth.js
To implement this I am using a library called Auth.js, formerly known as NextAuth. It is the de facto standard for authentication in Next.js. And the configuration is surprisingly simple. You define the providers. For Google, you need a Client ID and a Client Secret that you get in the Google Cloud console. For Discord, the same but in the Discord developer portal. And for email, you configure an SMTP server. Then Auth.js takes care of the whole flow: the redirection to Google, the callback when the user authorizes, creating the session, cookies… All that if you did it by hand would take weeks, here it is a few lines of configuration.
And this connects with the database, of course. In the User table I have the typical fields: id, email, name, avatar image… But I also have fields specific to Auth.js: emailVerified to know if the email is verified, and the relationship with Account which is where the connections with providers are saved. A user can have several linked accounts. In other words, they may have logged in first with Google, and then also linked their Discord. So if one day they log in with one or the other, they access the same profile.
Security with Captcha
Now let’s go with a topic that many people ignore when launching a project: security. And specifically, captchas. Internet bots don’t care if you are a multinational or a kid with a weekend project. If you don’t have captcha, they will find you and spam you.
So, what have I done? I have put captcha on all critical forms: login, registration, content upload, comments… I am using Cloudflare Turnstile, which is Cloudflare’s alternative to the typical Google reCAPTCHA. Why Turnstile and not reCAPTCHA? Well, because Turnstile is more respectful of privacy, it doesn’t track the user as much, and it also has a very generous free tier. For a project that is starting, perfect.
The implementation is simple. You have a React component that renders the captcha widget, and when the user completes it, it gives you a token. You send that token to the backend along with the form, the backend verifies it with the Cloudflare API, and if it is valid, you process the request. If not, you reject it. It seems like a lot of mess but it’s literally 20 lines of code. And you save yourself trouble.
Automatic Backups - The Most Important Thing
And now the most important topic of all. Really. If you only keep one thing from today, let it be this: make backups. Backups are your life insurance. If everything goes to hell, you can recover yesterday’s data and move on. Without backups, if something happens, you are dead.
What have I configured? Daily automatic backups. Every night, at 3 in the morning when there is hardly any traffic, a script runs automatically, does a dump of the database, compresses it, and uploads it to a cloud storage bucket. I keep the last 30 days of backups. So if I realize something broke a week ago, I can go back and recover it.
And the best thing is that once configured, you forget. It runs by itself. You don’t have to remember “oh, today I have to do a backup”. No. It’s automatic.
And an extra tip I give you: test the backups from time to time. Just doing them is not enough. You have to make sure they work. Every month or so, I take an old backup and restore it in a test environment. Just to confirm that it is not corrupt and that if one day I really need it, it will work. Because nothing is more annoying than needing a backup and discovering it was badly done.
Recap
Well, that’s how the project is going. Today we have seen quite a bit of meat: we have set up the database with Prisma, with a generic content model that scales well. We have implemented social logins so people can enter with Google or Discord without friction. We have added captchas so bots don’t burst us. And we have configured automatic backups to sleep peacefully.
And now, being honest… Is this website going to succeed? Well honestly, I don’t know. The market is very saturated. There is strong competition. I have had posts banned on Reddit. But hey, I’m excited to finish this. And I’m excited that you see the real process. That this is not like the videos of “I set up a SaaS in a weekend”. No. This takes time, there is frustration, there are days when you don’t even feel like opening the editor. And I hope that, if you have your own projects, this serves you for something. To inspire you, to copy ideas, or simply to see that you are not alone if your project gets stuck.
If you liked it, you know, leave a like that helps a lot. If you want to continue seeing how the project progresses, subscribe. And if you have ideas or suggestions of what you would add to a Hytale website, leave it in the comments, I read them all.
Thank you very much for being there, hit the code hard, and see you in the next chapter.



What do you think?
Leave your opinion, question or suggestion. Comments are synced with GitHub Discussions .