skip to content

Build a scalable design system for enterprise websites with Payload CMS & Next.js

How do you make the dream of a design system for your company stand up to the reality of other teams actually using it in prod? James Mikrut will show us how.

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning ( Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON: Hello, everyone, and welcome to another episode of Learn With Jason. Today on the show, we've got James. James, how you doing?

JAMES: I'm great. How are you?

JASON: I'm great. I'm excited to have you on the show let's start by setting some context. Do you want to give a background on yourself?

JAMES: I have a hybrid background. I started as a UI designer. I just had a natural interest in writing code, so I taught myself how to write JavaScript primarily, starting in 2010 or so. Then I kind of followed all the way through as a full-stack engineer for the last 12 years or so. So I'm half design, half development. I really sink my teeth into the React ecosystem and front-end stuff in specific. But I write TypeScript front to back. I'm the CEO of Payload CMS. Just went full time on it, actually. I've been in the agency world for the last seven years. We're closing the agency down, bringing all the employees over to Payload and just going full speed ahead on Payload. So it's a really exciting time for me.

JASON: Yeah, yeah, that's super exciting. Always a good moment when you're able to actually go full time on the thing, right? How long were you working on Payload CMS before you went full time on it?

JAMES: A couple years. My agency was using it as dog food for our own projects. And those projects were anything from a full e-commerce custom product designer to, like, an Uber for snowplows to enterprise websites, you name it. But we took a lot of care in the design of the API to try and reduce breaking changes as much as possible once we released it for public beta and now 1.0 production. So it's been years in the making. But we've been -- since 1.0, we released 1.0 in July of this past summer, and that was right in the middle of YCombinator. And I had a newborn.

JASON: Sounds like you've had a real boring go of it.

JAMES: I don't know what day it is. I don't know what time it is.

JASON: Yeah, no kidding. Geesh. So that's exciting. So I'm always curious when it comes to something like this. You were at agency. You built out Payload CMS, presumably to scratch your own itch. You had a need. You wanted to solve things in a way that you didn't feel was being met by the market. So here's a question. Is Payload CMS boot strapped, or did you end up taking investment for it?

JAMES: We built the entire thing, including all the way up to 1.0, completely bootstrapped. But we did just graduate from YCombinator summer 2022 batch. So that was our first investment we took. Then we just raised a bunch of money from some pretty notable investors, which we have an announcement coming out within the next month. It's going to coincide with our launch week, which is November 14th. We're going to do a fundraising announcement among many other things. So we're no longer bootstrapped, but for the first couple years, we definitely -- after hours, passion project, pouring our heart and soul into this. As you know, it's open sourced as well. So it's just fully MIT license, and we got there bootstrapped for sure.

JASON: Very cool. Well, congratulations on the raise. Look forward to that announcement. So let's talk a little bit about -- actually, I kind of want to do two things here. We're talking today about building scalable design systems for enterprise websites. This is sort of -- this is the holy grail, right. When I went over to IBM in 2016, one of the big things that they were struggling with -- my whole feed just went super weird.

JAMES: I see that, yeah.

JASON: It looks okay on -- hmm.

JAMES: Yeah, I think it's good. I think it's our little preview window that's jacked up.

JASON: Well, that's not good. Let's see if it clears itself up when it comes time for screen share. We'll cross that bridge when we come to it. Okay. So when I joined IBM, there was a project under way that had been under way for a while called carbon design system. The intention of this project was how do you get 30-plus teams who all need to build for the web who use Angular, Vue, React, Backbone, jQuery, no framework. How do you get them all to build something in a way that feels cohesive? And how do you do that in a way that doesn't require you to just wield the hammer of authority and basically tell people do it this way or you're fired? Right? And something that I thought was really unique about carbon was that they had the buy-in that they could have gone out and just, like, swung that hammer and said no, this is the way we do things. You either adopt this or you're fired. And instead, they wanted to win the hearts and minds of developers and actually get them to choose this design system. And it's hard. You know, it is an extremely challenging thing to do, to go out and convince people who, you know -- let's do a little philosophical aside. Are you familiar with the concept of dark matter developers?


JASON: So there's this idea that when you get on Twitter, you're seeing the loudest and most visible voices in development. And they're the extreme edges of the bell curve, right. The vast majority of developers, you know, there are millions of developers, they don't -- they're not on Twitter. They're not on social media. We don't hear from them. They're just doing their jobs. So for those developers, those dark matter developers, they're not in it for, like, the excitement of the latest framework or the drama on JavaScript Twitter. They're there because they've got a job, they've got to ship this thing, then they want to go home and spend time with their families or have their hobbies or whatever it is they do. At IBM, there are a lot of folks who don't identify as their career. They're not there because they live and breathe code. In a lot of cases, they've inherited systems that are really -- they're legacy code. They haven't been updated in a really long time. There are, you know, a lot of issues with it. It's basically so complicated at this point it's like what I've joked is an append-only file, where you know, it's a million lines of code and they can old add to the bottom because they don't know how to change anything at the top because it's all 15 years old. I don't know what happens when you delete that. So when you have got a group of developers who absolutely do not want excitement in their job, you can't go out and run a hype tour. Oh, we've got this amazing build or this new component system! It's going to change everything! It's going to be so nice and modern! They're like, I don't care. Don't make me do work. Don't touch my stuff. Right? Like, I got tickets. I need to get these tickets done, and then I want to go home. So what you're talking about is an extremely challenging thing, right? At least in my experience. So how do you approach this? I guess what led you to even think that this was the right topic to try to tackle?

JAMES: So I have to draw an important distinction. Like, carbon design from IBM and material design from Google, those are like true visual design languages that, like, focus on the very, very granular pieces of a UI language, like shadows and depth and what pixel-rounded edges you need for many different components. There's, like, an infinite depth to that entire arena of work, but what I'm going to focus on today is actually more about how to set up like a tool for editors to use. It's more about giving control but not giving too much control. Because if you think about a page builder, like Square Space or any of those, even Web Flow to an extent, you get so much control and then your editing team goes crazy. Then they have red paragraph and bold, italic, underline all in the same little area. They just get wild with the tools they're given, and they have too much control. They end up creating a Frankenstein out of the tools that you've given them. So for me, today's topic will be about how to structure a CMS and then the front end that corresponds with it to deliver enterprise editors with the flexibility that they need to be able to maintain a large web project over time but not allow them to go off the rails and create the Frankenstein we want to avoid. So the design system that I'm talking about is like maybe one level up of the minutia at the shadows and border radius, and it's more about how you structure a CMS so you deliver just the right amount of control in a very deliberate manner so that it can't be hijacked and manipulated, right. And I'm passionate about that. For me, being that I sit on kind of the design and development table both, I've had to design and build large CMS for a lot of my agency clients. One of them was Klarna, actually, in 2019. They had, you know, 30 content editors from all over the world. There was a site for Germany, for Sweden, for Australia, North America, UK, and they all had to use these same tools but to express very different messages. So how do you design these tools and then equip content managers with tools that they can be productive with but not go off the rails?

JASON: Got you. Okay. That makes sense. And so is this the, like, intended purpose of Payload CMS? It's that pairing with the editors and the developers to try to set up the right guidelines? Or is this an application of Payload CMS?

JAMES: I think it's an application of Payload, and I think we got to get a little philosophical again for a second.

JASON: Let's do it. This is my favorite part of the show.

JAMES: So right now, there's one blanket term to refer to anything like what Payload is and what Strappy is and Sanity. Content management system, right. But in reality, content management system is thought of as managing content for brochure websites, right. Like you use a content management system to power a website. But in reality, content to the internet means a lot more. Like, let's take for example Spotify. Someone at Spotify has to manage album art and playlists and artist descriptions and all of the metadata that goes with that. Then the content gets used in apps. It doesn't get used in a website, but it's still content that powers the internet. In the same way as that, you could, with a content management system that's appropriately flexible, you could manage orders, manage shipments, manage requests, manage customer profiles. All of that is content that you need to have an admin interface to manage. But is that really a CMS? It's hard to put a label on it, right. So I think the industry as a whole is kind of needing a better label for the power that managing content represents outside of just calling everything a CMS. So the reason I'm saying this is because I think Payload, one application, is to power websites in the right way so that they can't be turned into Frankenstein, but Payload is much more powerful than that. It actually borders on an application framework because of our deep access control and because of our hook-based infrastructure and all this server-side stuff. So I wouldn't want to trivialize it by saying this is the only thing it's good for, but that's why we just picked the label CMS for now. Because that's what everybody resonates with. But I think there's room for improvement there.

JASON: And you bring up something interesting, which is kind of touching on what I'm starting to feel as a bit of a sea change in the way we relate to the internet in general. I feel like when first started building for the web, the website was sort of an add on. The app was an add on. And you would use it as a bonus to go along with the retail experience or the in-person experience or sitting down at the restaurant. Now the website for, you know, betterment, for example, the financial institution, that's their entire experience. I don't know if you can even get a person on the phone and have a phone experience. They don't have branches, so you can't walk in anywhere. There is no real-life experience of betterment. The website is everything.

JAMES: Absolutely.

JASON: And their app and web interface is the whole thing. And that fundamental shift has really pushed a lot of things that I think would have been considered specialty, like a deep content experience for an ultra complex set of inventory management or whatever it was. It kind of felt like for a while we looked at it as, well, if you have really complex inventory, you use something like Shopify. Because they're built for managing inventory. And anything else is just content, right. So just put it into a CMS. So you bring up a really good point that we've sort of evolved to an additional layer here where the web is the primary entry point for the vast majority of businesses, and for many businesses now, it's the only surface area. Which means all of that complexity is in the web now. And we have to be able to both as web developers, you know, think and reason about it, which is why I get so excited about things like serverless functions and edge functions. It flattens that learning curve of dealing with that complexity. But then you also have to think about how you manage, you know, how do the people who work on the website work? What are the ergonomics? How do you make sure you don't create this Frankenstein mess of people have unlimited flexibility and will absolutely use it, you know. We've all seen posters designed in Microsoft Word by somebody who didn't have any constraints. And that's clearly not an acceptable way to move forward on the web. So this is interesting. You're in a cool space here. And I like the angle. I like where your head's at.

JAMES: Yeah, you know, it all just kind of arose out of necessity, like you said early on. Because my agency was building pretty complex things, and we'd have to kind of assemble different technologies. Sometimes we would build a Laravel app if we had super complex stuff. But we've built this as like a silver bullet solution. You own the back end as well as the front end. So you can build any type of functionality, integrate with any third-party service because you've got the back-end infrastructure already. And it's just the beginning, you know. We've got a lot of stuff in store. And I'm pretty excited about it. But the industry is changing, like you said. Content is critical, and to power critical infrastructure, you need to have a tool that you can rely on. That's what we're trying to do.

JASON: Got it. Got it, got it. Okay. So let's talk through a little bit of what we're going to do today, specifically. So we're going to be working with the Next.js app. We're going to set it up with Payload CMS. How do you -- like, what is the overarching goal for what we're going to accomplish?

JAMES: So I have three things. Number one is a Figma file. Number two is the CMS repo itself. So the Figma file gets translated into the CMS. And then we're going to have a website repo on Next.js as well. All of it's built in TypeScript on both the CMS and the Next side. But you can see the progression of going from Figma to the CMS to the website. And we can just go just review them all. I don't think we really need to write any code today unless we find something we want to play around with. But my team and I just kind of splashed out a bunch of stuff over the last, I'd say, 24 hours. It was kind of a mad sprint here, but we got some cool stuff done, and it should be -- let me share these with you real quick. It should be pretty cool.

JASON: Nice. All right. Well, while you're doing that, I'm going to flip us over into our Next view here. We're going to move over into the pair programming view. I'm going to move the cameras off so we don't get inception. Here we go. And so first, let's do a shout out to the captioning. We have Rachel with us today. This episode, like every episode, is being live captioned. That's through White Coat Captioning. Thank you very much. And that's made possible through the support of our sponsors. We have Netlify, Nx, and New Relic and soon Plural Site. Still working on that paperwork. We're going to have the support that allows this show to continue to function. So, thank you all very much for that. We're talking today to James. Make sure you head over and give a follow on the Old Tweeter. And we're talking about -- I'm in the wrong window. We're talking about Payload CMS. I'm making a guess. There it is. Make sure you go over and give that a follow as well. All right. So at this point, I have installed MongoDB. Let's make sure that worked. What is that?

JAMES: I don't know. Usually it would just tell you the version. Looks like you have it, though.

JASON: Do I need to -- brew services. Oh, I have to actually start it. That's what I did wrong. So we'll start it.

JAMES: Looks promising.

JASON: Still no. Let's see. Oh, don't you tell me I have to restart my computer for this to function.

JAMES: We can just get a Mongo Atlas, too, if we want.

JASON: We might need to. Brew services restart. Why do you think I need Postgres? Make sure Postgres is stopped?

JAMES: Oh, maybe does it run on the same port?

JASON: Same data directory. You can move to a different one. Why is Mongo using Postgres at all?

JAMES: Looks like it's probably just conflict of the place that it stores the data. Well, we probably could get pretty far without even needing the database. Like, we could pull up the Figma file and review that.

JASON: Yeah, let's start there. Then we can start digging into the other pieces and solve those problems as we get to them. I've learned my lesson. I'm going to set up the database ahead of time next time.

JAMES: That's all good. We'll figure it out. Okay. So you can actually click on my pointer there. Yeah, then you just follow me. But basically what I've got here is just a quick-and-dirty Figma file that goes over principles we tried to bake into our front-end framework when we translate CMS building blocks. There's a couple very important, like, fundamental rules that if you follow, everything will become a lot easier. The first one is just setting your type properly. This is no surprise to anybody, but typically, the designers at my agency would go through and create type styles out of a different heading and maybe some branded elements as well. So maybe we have large-body copy in addition to the headings. Then a label and just some button styles here. Like this is all meant to be pretty wireframe and not highly designed. More so just to show the intent of the different pieces that build up a typical CMS. But we also show the margins. So this heading one here has 72 pixels on the top and 48 on the bottom. 60 and 48, blah, blah, blah. Then we do this for each break point. So this is the large break point here. And then we have another set of type styles for the laptop-size break point. Then we have another one for mobile. If you lay this out like this in Figma as a reference, then your engineers that actually have to translate the site are going to have a lot easier of a time just translating all of this stuff over into CSS. So when we clone those repos down, we'll be able to see how they translate into the CSS. But this is pretty much where we start. And it's just a quick get everybody on the same page and have a source of truth for the type sizing and the hierarchy. This is just all the system font, so it's SF pro whatever display.

JASON: Right, right.

JAMES: But yeah, so after we define the type and the buttons, we want to talk about block spacing. Block spacing is something you can quickly run into a lot of problems unless you very, very clearly and deliberately structure it. So typically for a lot of websites, you have different background color blocks and the funny thing about those is what I'm looking at here is like three blocks. Content block, content block, content block. The first one should have 120 pixels padding on the top. But if the second block is the same background color as the first, it should have less space between them. If you doubled up the 120, that's going to be a huge space between the blocks, right? So you want to have some programmatic way of enforcing block spacing that blocks of the same background color can collapse their margins on top of each other. And maybe I skipped a little bit of this, but generally, everything that we do nowadays is going to be on a layout-building mentality, like a block-building mentality. So all the big CMSs do this really well. Prisma has slices, which are great. Contentful, you can build in references to other content models. And you want to craft your page content on a layout-building mentality. But when you give that control to editors and you don't have a very good mindset over how to space the blocks from one another so that the vertical rhythm is always going to be build on your baseline grid and it will always be appropriately spaced no matter what the block background colors are, right. So if you switch to a dark background, bam, you're going to need 120 pixels again. But if the two blocks are the same background color, then they should condense and be smaller.

JASON: Gotcha, gotcha.

JAMES: So we try to spell all of that out as much as possible. Then we try to programmatically enforce it when we get to the front end in the Next.js stuff. So we've got a lot of that stuff to show as well. But this is huge. This will help your site feel consistent and structured rather than if you're defining block spacing all willy-nilly on every single block and it's different everywhere. It's going to lack that vertical rhythm that's so necessary.

JASON: Right. Right. And as a big fan of willy-nilly myself, I have to agree with this. It's not right everywhere.

JAMES: Exactly. If you can enforce it programmatically, you're going to get aesthetics as well. And the other thing is if you're putting text inside a block, you need to turn off the first child's top margin and the last child's bottom margin. This is wrong because this is going to create too much space. So you have to automatically disable the top and bottom margins because we have on our -- what is this? H4? We have 36 pixels on top of it. But if you keep that, your rhythm is going to be all crazy because you're going to have the 36 pixels up here, and it's going to overlap. You're going to create extra space. So you have to turn that top and bottom margin off for your first and last. Again, doing that programmatically is going to be the best bet because you're editors won't be able to screw it up.

JASON: Exactly right. I think one of the big pieces that is really challenging with this is as engineers, we are -- like, we have a tendency toward configuration. And we think to ourselves, well, somebody might need that. So I'll just add a switch for it. You know, let them set that to true if they need that margin. Or margin collapse true. Something like that. You start making all these configurations, but when you hand this to an editor and they open the page and it's just a thousand check boxes, they're like I'm just not going to use this. Immediate overwhelm. Or worse, they just start checking buttons and they're not 100% sure what they do. Then they don't go back to a default so it just ends up being kind of messy. Or each one -- this is always my favorite. Each one adopts their own signature style, as all of white house have received an email that was clearly edited to use, like, Comic Sans or something. Ah, I see you found the font setting in your email editor, right. You don't want your CMS to have that same option, where somebody can be like, well, I want every page I write to have a signature style.

JAMES: I could not have said any of that better myself. You don't know how many times I've built a CMS and I've included the check boxes for, like, turn off top margin, turn off bottom margin. Padding top, medium. Padding top large. Giving them too much control like that is the killer of any good UI. Honestly, even the most power users of your CMS probably don't want that. They probably want it handled for them. So if you can come up with a mindset of building that interior structure, your project is going to be more successful. And that's pretty much like the ethos of what I'm trying to show today.

JASON: And I think the other thing to consider for folks looking at this saying I want that setting, what job is somebody showing up to do when they use a tool? You know, I'm an engineer. I'm showing up because I need to tweak this stuff. So of course the job I need my tools to do is to give me that optionality. Maybe my components let me do that. But as a content editor, the job I'm showing up to do is putting content on this website. I'm not there to design. I'm not there to configure, and if I have to, it takes me out of the job that I'm trying to do and into a different job. And that context switching is hard. And it also puts people out of their expertise. An expert writer is not necessarily an expert designer and vice versa. And that's why we don't want designers writing ad copy and we don't want advertisers writing -- like doing our designs. And the CMS needs to respect who's here to do what job and make sure that they keep sending the right context.

JAMES: Exactly. And it's funny. In the comments right now, we have Ben Myers saying he wants red, bold, upper case, underline, and italicized. Maybe we can make a special CMS for you.

JASON: (Laughter). That one just publishes to nowhere, Ben.

JAMES: That's called brutalist design right there. Have fun. Yeah. No, I think we're really on the same page with all of this so far. It's good stuff. But yeah, this is where we start. And this little Figma exercise here is very rudimentary. We didn't put any time to making this beautiful from a design perspective. It's utilitarian. It's supposed to be the nuts and bolts, the core ideas. So obviously we didn't pick the fonts or anything. I think with this, this is just kind of a quick style guide. We usually write up some rules, how to break it down on laptop, mobile, large, stuff like that. And then we just kind of set up the road map for when we go to start writing the code. We have an exact understanding of what we're going to do. So with that, let's look at the second part of the Figma file, shall we?

JASON: Let's do it. Where do I go? Oh, I'm following you.

JAMES: Yeah, you can just follow me. So with any website, at least for my agency the last probably four years, this is our kind of paradigm. We break up the website interface into the hero section, which is above the fold. That's like the -- "above the fold" in quotes, I guess. The fold doesn't exist. But the hero section, this is what a lot of people consider as a template, which it's not a template. It's just the first block on the page. Heroes are kind of going to need to be visually distinct from one another. Like on a homepage, you're probably going to have a high-impact, very graphical, like something that's going to make a branded statement. Then when you get further into the website, you're going to have more utilitarian heroes that maybe have a couple jobs to fill. Maybe a couple calls to action. Then the tertiary pages like privacy policy and things like that are going to have the lowest impact. Just give me a headline and get to the page content, right.

JASON: Right.

JAMES: But that first section, the heroes, what we try to do is come up with a set of heroes. When we're doing the UI design, we say what does this website need to do? What are the heroes we need to build? Oftentimes we'll end up with like eight to ten of them, maybe content and media, maybe a slider, maybe full screen image background, maybe a video background, maybe some kind of broken grid. Whatever it is. The branded heroes, like, that's the first item on the page. So on a page-by-page basis, you're going to choose which hero you want to render. The hero is not a layout building block. The hero is a static one-off thing per page that you choose to render. For this example, what we've got is a high-impact hero, which is just real quick and easy. Like an image and some calls to action and a headline with the large body. Then we show the grid. So it's a 12-column grid. Everything is based on 12 pixels baseline. And it's as simple as can be, right. The design isn't crazy, but the idea is that the editor should be able to choose from the heroes, and the first one we have is the high-impact hero that could be good for a homepage or a campaign page or whatever. By the way, I have a cold, and I can barely breathe. So if you feel like I'm breathing through my nose, it's because I -- yes, I'm dying. So, cool. But yeah, so this is the large break point. This is like 1920 pixels, similar. Breaks down to a laptop screen size. The gutter gets a little smaller on the outside there. And the grid gets a little more condensed. Then the mobile. But this is all the high-impact hero. Then we have another medium-impact hero. Just a little less from a visual perspective. Still has an image. Breaks down on mobile. Finally, we have the low impact. This is the utilitarian one. Just straightforward. No imagery.

JASON: Got it. Okay.

JAMES: If you can choose which hero on a page-by-page basis, then you can craft the user journey from the landing page all the way to the conversion point by starting high and ending up utilitarian inside lower-level like into the user journey. So typically, this is just three different heroes, and you can name them whatever you want. But the idea would be that you build your CMS to have a very static set of deliberately designed hero options. Then from there, you start to leverage the layout builder itself.

JASON: Right.

JAMES: But the layout blocks are separate than the hero. So you choose the hero then go into the layout blocks. The layout blocks are meant to give variety and versatility. Maybe to get a little philosophical once again, even though I'm a designer, I firmly believe that a successful design does not start by painting a pretty picture or starting in wire frames. It needs to start around the message or the problem at hand and the solution through the content of the page. So for me as a designer, if somebody asks me to build their website or design their website, I'm going to say, okay, what's your message? What do you need to do? What's your content? What do you want to do with this website? And it's really going to be up to the content to determine the shape of the page, right. Every page, the, quote, design of the page is based on the content.

JASON: You're bringing up what I think is what I notice to be the fundamental tension of block builders and thoughtful design. What you end up with is, okay, so the message dictates we need these things to exist. The blocks dictate that everything needs to fit into these boxes. One of the main tensions that I see come in is that you've got a very thoughtful layout builder that cannot service the needs of the message that needs to be sent. So then people talk themselves into a, well, just this once we'll do a one-off bespoke landing page. Just this once we'll do it as a microsite instead. Then we'll clearly maintain that. And then you get this sprawling maintenance burden of like, welt, we one-offed that thing, we escaped the design system for this thing, we made a microsite for this launch, and now all of that is aging. Because it's not maintained with the rest of the system. So as we're looking at -- so you've got these layout blocks, right. When you're starting with your message, how do you make sure that you've got the right amount of flexibility in your layout blocks to support any message?

JAMES: Really good question. So we actually, at my agency, would never even start identifying what layout blocks we need until after we've gone through a very thorough wire framing process. And when I'm saying wire frames, a lot of people think of wire frames and splash something together with boxes with Xs in them. You just check it off your plate. As a designer, yep, I did my job. I did wire frames. But in reality, it's so much more important than that because what you do is you take the message from the client, you take the message from the project, and you distill it out into, okay, we have this job to do on this page, we have this job to do on this page, we have this job to do on this page. Do we see any overlap of these different jobs? Can we find the lowest common denominator of these pieces that need to play together and design for the message? We identify what layout building blocks we need based on what each page needs to do. So you don't say, like, hey, content editor, here's your six blocks, have fun. Write your message according to these six blocks. You say content editor, what's your message? Let me design you some blocks for your message. And you try to be as holistic as possible from square one. So right when you start, you don't go start pulling stuff out of thin air. You work with wire frames. You try to massage the content into appropriate layouts that are effective. Then you figure out the lowest common denominators and extract those into your layout blocks.

JASON: Got you. I understand. So it's not really like -- because originally you said you start with the message and then you go to wire frames. But you even -- like, it sounds like they're kind of in the same thing. Like the message drives the wire frames, the wire frames drive the presentation. When you start looking at the presentation as something too, you can see its visual weight and say that's too much on this message. Let's de-emphasize a little there. Or this needs to be two pages. There's too much content for this to be one page. I like it when it feels collaborative like that, where you've got somebody who's the message person, the content owner. Then you've got a designer. Then you've gotten a engineer. All kind of looking at things from their own perspectives and helping pull out a simplified system. This is challenging, right. I think a lot of companies either don't have the processes in place or don't have the collaborative muscle built to really facilitate this kind of, like, hey, let's get everybody in a room and work on this at once. It's like, you do content and then you throw it at the designer. The designer will take the content and turn it into a wire frame and throw that at developer, who will turn it into a thing. So this is -- I like where your head's at on this.

JAMES: Absolutely. Like, wire frames -- I'd like to stress the importance of wire frames, and I'd like to say the majority of the design and the thinking actually happens here, rather than the UI phase that would follow that, from my process, really. The UI phase is really a designer's job. If you're going to be applying branding to wire frames, then the content writers should have little to no overlap there. But in the wire framing stage, just like you said, you've got to get the engineering involved. You've got to get the design thinking involved. And you got to get the writing involved. And there needs to be a collaborative process here. If nowhere else, it needs to happen here. And if you do your job right here, you'll have an easy time throughout the rest of the website.

JASON: Mm-hmm. Yeah, headunderwater is chiming in to agree. I think that's -- yeah, it's saying tell me what you need instead of here's what you need. I think that's such a subtle but important distinction when you're working collaboratively to make sure you don't start by saying I have a solution. You start by asking what problem needs to be solved.

JAMES: Absolutely.

JASON: And it's so, so -- I mean, I am the worst at this. I love jumping to a solution. Somebody is like, we need a new landing page. I have so many ideas! Instead of saying what for, why do we need to make this, who is it serving, who benefits from this existing, why is this more important than the other list of things we need to do. Like, who's asking these questions if it's not me? And I think that's a really challenging skill because it's fun to build stuff. I totally want to go do a new design. That sounds like a blast. But we got to start with why. What purpose does it serve?

JAMES: Well, you know, I feel like a lot of this industry gets a bad rap because they don't follow these principles we're talking about right now. Exactly what headunderwater just said. Tell me first what you need. If you go on, there's a lot of really beautiful work on that website. But it's all so designed. It's all -- you can even miss the message, and 90% of the website is on there because there's so much happening you just want to scroll and you're looking at the interactions rather than reading the messages. To me, that's always a little backwards. To really be successful in a business goal, you need to say tell me what you need as a designer, rather than here's what my shininess just came out like. It's backwards, if you do that. And I feel like a lot of designers fall into that trap. They end up making beautiful things, but are they utilitarian? Are they useful? Maybe not. It's a classic trap.

JASON: Absolutely. Yeah, if you want to make art, make art. But remember -- I went on a little mini rant about this on Twitter not too long ago, about how people who are doing this job because they want to do their hobby professionally can do a lot of damage because they're not looking at it as, like, I'm here to do a job and I want to do this job as well as I can. They're looking at it as I get to play with my favorite toys for a living, and I'm going to play. And I don't care if I'm doing a good job.

JAMES: Exactly.

JASON: And that leads to a lot of unnecessary rebuilds and the stuff that you see on awards where it's just clearly somebody was like, what if I could make the design do this, and the message is what they filled in to make the website not just text. It's not about the message at all. Yeah, this is a business, not art school. That's a good way to put it, headunderwater. Yeah, so anyway. We've got layout blocks here. So we talked about heroes. We've got some layout blocks. Let's keep on moving so I don't completely burn the whole time here.

JAMES: Yeah, I can talk about these types of things for a long time. So yeah, let's keep moving. Okay. So like I've been saying, this is very rudimentary. We have three layout blocks for the purpose of this tutorial because I want to show how to scaffold them and connect them so that the editor can drag and drop and build things. But the content block is going to be pretty multifaceted. What we've got is maybe a type field where you can choose between what layout you want. We're not building a column selector. We're not doing add column, add column, add column. We're saying choose what layout you want. Is that a single column? Okay. Is this a half and half? Is this two-thirds, one-third? Or is this three column? Those are the only options. They can't go crazy. They can't do a one-fifth, four-fifths. You know what I'm saying? They can't go crazy with any type of column system they want. They're not going to set their widths themselves. They're going to choose from a drop-down what lay you want do you want. Then we need to render them the appropriate rich text editors to fill up those contents based on what type they choose. So if I turn on the grid, that leaves us to make some pretty, like, deliberate design decisions. For example, one-column content block, if this was stretched all the way over here, that's not going to be good for anybody. There's that classic rule in the design world. Limit the amount of words per line so that it's comfortable to read. You don't want to have a 12-column, 1-column block. So we can restrict that to nine columns and keep that a little easier to read. If we do that with a select field where they drop down and say, okay, I want a one column, then we can enforce that on the editor. And they will have no choice. They have to deal with it. We as designers can back that up when we say, oh, you can't have that be wider because it becomes uncomfortable to read, right.

JASON: Yeah, exactly. And these are these little things. Like, at some point, I just learned there was a maximum scan length for lines before it became hard to read. I don't know where I learned that. I don't know why I remember it. But it's just a thing I do that most people who have not worked as a designer will never -- like, why would you ever think about that? Sometimes you look at a design and go, that's kind of hard to read, but you don't know why. So you just sort of, well, yeah, I'll let somebody else fix it. So letting the system solve these problems is such a critical thing to think through.

JAMES: Absolutely. That's what we try to do. Each one of these columns has the ability to add a link below it. That will all be hard coded. The link will only be able to go after the rich text field. So you can't have a paragraph and then a big button and then another paragraph because that's going to look all manic. You want to restrict those things as much as you can.

JASON: Absolutely.

JAMES: They'll all stack the same on mobile. Then we have a media block to show a different type of block. You can have it centered on the screen or full screen. Pretty straightforward. Not a lot to see there. Then the last someone the call to action. This is a little banner with a background color and some buttons on the right-hand side. But let's say that this -- generally we're going to have 15 different layout blocks that are very versatile in design in nature so the editor can craft visual styles throughout the entire website, especially if you're doing an enterprise website. You might have 300 pages, each with very different content needs. So your library of layout blocks can be much more than three, but as long as each one is very deliberately designed and constrained so that they can't hijack the intent.

JASON: Right. Right, right.

JAMES: So what we'll do is we'll go take a look at the CMS. I guess we should probably sign up for Mongo Atlas. If we can't do that, we can always look at the code on GitHub. This will all be open source, and we can even put the links to the GitHub somewhere.

JASON: I think I have an Atlas account. So let me see. I'm going to see if they -- wait. What if I already signed in? Because I could have sworn that I did this already.

JAMES: Todd, accessibility. That's a great question from the comments. Everything should be built with accessibility in mind. And admittedly, I'm still learning a lot about that because I feel like it's a moving target. Over time, things change and accessibility needs to keep up with that. But all of the design system, every layout block should be built with accessibility in mind. I don't know if that's a cop-out or not to your question.

JASON: Are we in? Is it happening?

JAMES: Something is happening.

JASON: Something is happening. We're waiting on Google Ads.

JAMES: No ad block?

JASON: Oh, no. Let's see. Come on now.

JAMES: I don't have ad block either, actually. I should.

JASON: I always think about it. Like, oh, yeah, I'm going to do this. Then as soon as I turn it on, things break in weird ways. Then I think that apps have bugs. I'm like filing false reports, like turn off your ad block. So I just keep it off. Whatever. It's fine. Okay. So I have an account. Let's see if they'll let me create. Oh, come on. Is the internet going slow, or are we having a little issue on Mongo?

JAMES: I'm seeing some pixelization in your web cam here and there.

JASON: Let's see. How many services can I run on my computer at the same time before it explodes? All right. We're going to call this Payload CMS. Don't need anything special, right? Just create a project. While we're doing that, I'm going to reload these. So here's the CMS. I need to fork this, right?

JAMES: You can just clone it. Just clone it down.

JASON: So I'm going to move into my GitHub here.

JAMES: Yep. Then the only thing you should have to do is cp.env.example. Oh, yeah, you'll also -- do you use yarn?

JASON: I can, sure. Do I have it installed? I don't have yarn installed on this computer. (Laughter)

JAMES: So just make sure you pass legacy peer devs.

JASON: Like this? Or camel case?

JAMES: Exactly like that. So dash deps. Yeah. Nailed it. Then there's an env example. You can copy that and make a real env out of it.

JASON: Got it.

JAMES: And that will have your connection string to Mongo inside of it.

JASON: Got it, got it, got it. Okay.

JAMES: I think that's pretty much all you need. Payload is all code based. So everything is contained right inside the repo. No migrations.

JASON: Nice, nice. All right. So come on. Somebody is like at my door yelling. Let me just close this real quick.

JAMES: Follow your heart.

JASON: Don't know what that's all about. So then you said copy the .env.example.

JAMES: Then you want to vim .env.

JASON: Oh, here we go. We're in vim. This is the rest of the episode. Soy need to set up my Payload in secret. Which I'm going to do over here.

JAMES: Yep, so build a database. Just do the free. That's probably fine. And yep, that's all good.

JASON: That's all fine. We'll put it in Oregon because that's close to me. All this is good. Here we go.

JAMES: Looks good.

JASON: Username and password, right?


JASON: So we'll do one of these. And one of these. Let me autogenerate, actually, then I'll copy that. Now, is it going to give me --

JAMES: Yep, you're going to want to do local environment.

JASON: Okay. Do I have to put my own .env in here?

JAMES: You might have to get your IP. If you just Google what is my IP and put it in there, just to be safe.

JASON: Okay.

JAMES: Yeah, just pop that bad boy in there. When can say? It's probably going to change too.

JASON: It'll be fine for now. So we'll do that. Go to databases. Then when I connect, is that going to pop up the string unencrypted?

JAMES: I don't know. But that actually -- yeah.

JASON: Let me just pull it off screen.

JAMES: Then you want to put it in that env file and never open the env file ever again.

JASON: Yep. Okay. So here is my -- I'll pull this over here. I'm going to -- oh, my god, I just remembered how to delete to the end of the string. That was magical. Where the heck is the -- is the Payload secret? The password I created?

JAMES: Nope, just type in a random string. That's used for salting the passwords that are saved in the database. Just crypto hashing string.

JASON: Get off here, otherwise you're going to show all my stuff. There we go. There's the password. And escape. I have quit vim, everyone. So that's done.

JAMES: So you should be able to just run yarn dev or npm run dev. And we can see if you can connect to your database or not. Nope.

JASON: App crashed. Bad auth? I did it. But I did it, though. Let me see if I need to do anything. Okay. So it's not actually showing the password. So they escape here. I created the password. I did that. Ensure any option params are URL encoded. I did that.

JAMES: Yeah, that should be it. The only other thing I would think might be wrong is if your IP already changed. It's definitely not static, right? Still the same.

JASON: Looks the same. So why are you like this? All right. Chat, just don't blow my stuff up here. Let's just double check this .env. Do I have so quote anything?


JASON: So this is correct.

JAMES: Yeah, that looks good.

JASON: All right. What the heck are you doing then? Try one more time. Cannot connect to MongoDB. Bad auth. So why would it have bad auth? Can I set -- you can't just tell it to allow, like, any -- I want you to allow any connections. That's all. Edit configuration. I did this before. I don't know why it's not working now. Shared, right. That's all correct. Turn on. Yeah, that's all fine. Now I can't even find that thing. Connect on your VSCode. That's not right.

JAMES: If you do the compass one.

JASON: That looks exactly the same, though.

JAMES: Does it? I think there's a few less options there at the end.

JASON: Hmm. All right. Let's just delete some options. Still doesn't like the auth. So I don't know why it doesn't like that auth, but maybe we just need to look at the code here because we're going to run out of time otherwise.

JAMES: Yep. I think that's fine.

JASON: All right. So let's do that. I'll pull it up in here. And we can peek at it.

JAMES: There's going to be plenty to see if we just look at the code anyway.

JASON: Great. So I'm in the code.

JAMES: Yep, okay. So a Payload app is basically an express server. So the entry point is server.ts. And it uses your own express server. So in the future, we're going to create some way to deploy this to lambda functions or even edge functions, but for now, this is all how it is. So you just create a new express server and run Payload data async. And list it on your express server. So if you want to mount any other express routes or if you want to continue to maintain functionality outside of Payload, you own your own express server and can do whatever you want. But for example, one of the cool things we're doing in this file is seeding initial data. You can see on line 24 right there how we're seeding. If we have an environment variable called Payload seed, then it will just automatically create a first user and create a home page for you and upload some media. So let's go into that seed script and take a look at that.

JASON: Okay. That's coming in from seed.

JAMES: Yep. So this is all with Payload's local API. It's just an async function that will create a user. That's just a simple dummy local-hose user. Password is test. But then we're creating a media document as well and actually uploading local JPEG directly from our Git repo into the database and into our cloud storage. So there will be a photo we can use in our posts. Then we're creating some homepage JSON and replacing a bunch of media relationship IDs there. So replacing that with image ID, creating a page, creating another page, and then finally, we're creating the main menu. The main menu there is a global. So this is something that Payload does that a lot of other CMSs don't do. Collections are many documents of the same shape. But globals are a singleton. There's only one. So you can use them for headers, footers, menu structures, things that don't exist more than once. So we're creating that right there. And that's it. It's all just seeded data. When we fire this up, say we could get Mongo working, then we would be able to instantly see all this information in the database.

JASON: Very cool, yeah. And then, all right, so once we're in here, these are just the actual data of the page. Structured data is always nice. You can kind of figure out what's going on. Pretty straightforward. So we've got a block called hero. It's got a rich text type. It has children in it. I love stuff like that.

JAMES: So then let's go to the payload config. It's the entry point for any Payload app. This is how you completely define everything that Payload specifically does. So we looked at the server. But that didn't have anything about hour collection schemas or anything. All that's done in the Payload config. It's all TypeScript. You can import React components. You can pass React components directly to the fig, and it will render it in the dashboard. Everything is done right here. This is a pretty simple one, but you can see we have three collections. Media, page, and users. Then we have the one global for main menu. If you can go into pages, we'll look at that real quick. Pages are set up to be a collection config. We have versions and drafts enabled just by passing drafts true. So that will allow you to maintain draft copies before you publish it. Then you can preview those in your front-end environment. Access control read is set to only allow people to read published only, which is pretty cool.

JASON: Okay. I'm going to click into that because it's -- okay. So basically you get to say only the users own stuff or only logged in users.

JAMES: So this is saying if there is a user, then they can read whatever they want. Return true, they read whatever they want.

JASON: Right.

JAMES: But if there is no user, then we're going to return a query constraint that dynamically restricts which documents can be read to only those that have a status of published.

JASON: Gotcha. So this is the, like, by default, the public role is anything you've published within the CMS is visible because it would be visible on the website anyway. So you don't have to worry about somebody hitting that end point.

JAMES: Exactly, yeah. And there's all kinds of access control stuff you can do. You can restrict, create, read, update, delete versions. Everything you can do right there. But the cool part is by returning that query constraint, that dynamically gets built up when we go to fetch the data. So it's a granular security system that lets you build any type of access control you can think of. It's much more than role based. Although, you could do role-based access control if you wanted to.

JASON: Gotcha. Yeah, I understand. So then we're defining our fields. And then Todd has a good question about the -- like, is it keyboard nav? I know I can't get Mongo running. I can't actually open this up to try it. But if I'm in, can I do keyboard nav through the whole CMS?

JAMES: Yes. Yes, you can. It's an ongoing effort to improve it. For example, the rich text editor has 16 tool bar buttons in some cases. Sometimes you might want to skip those. So we have a skip to input button we want to build. There's just basically a never-ending amount of improvements that we can make, and we're going to start focusing on that seriously. But yeah, you can navigate around with the keyboard for sure.

JASON: Nice. And then DerTieran is asking does that include an audit log, who published what at what time?

JAMES: Yes. You can dif them too in the CMS.

JASON: Oh. Love a good dif.

JAMES: Yeah, the package -- ah, I'm not a big fan of the package we use, to be honest. It's very impressive, but they haven't updated to React 18, and it hasn't been updated in a minute. So that's why I had to do the legacy peer deps. They don't support React 18. But if you want to dif what version was created or updated by who, you would just have an updated by field that gets dynamically populated by the user, like using a field hook. So then that would store on each version whenever anybody creates a version of a document. You'd be able to dif and see who created that document.

JASON: Gotcha. I understand. Cool. Yeah, that's great. And the difs are always so useful. I have a technical question you're free to defer on. How are you actually managing that? Are you using CRDTs, something else?

JAMES: The actual versions themselves?

JASON: Yeah, how are you managing those difs? How to you keep track of that type of collaborative thing?

JAMES: That's a good question. So because we're using Mongo, we can store -- we have another separate collection for the versions for any given collection. And we just store the entire document. We give controls to say how many versions do you want to store before we start deleting the old ones. Then you just dif the entire document against the currently published one.

JASON: Gotcha.

JAMES: We did that very intentionally because that way if you want to merge in fields, like if you want to read a draft post, you want to merge in some fields from the published to the draft to create one full document, it's a little easier. Also, for access control reasons. Because the same way that you can return a query constraint from that read access control, you can do the same thing for versions as well.

JASON: Okay.

JAMES: And all that does is just builds up a Mongo query that you can get very granular and say these versions should only be readable by the public, and these are readable only by the users. But this right here, what you're looking at, see that fields hero on line 33? So the UI, and I think -- so anybody that's watching this, you can pull up this code and run it on your own machine. But we have it split up into tabs. The first tab is a hero tab. If you go into that line 33, that hero, the cool thing about Payload is because it's all config based, you can organize your fields and reuse your fields and abstract them into separate files and do whatever you want, all in TypeScript and make it really, really maintainable and extensible. So this hero field might be used in other types of collections in the future, so you put it into a field, like another file. Then we just import it and pass it to the config. It's not JSON. It's full TypeScript. So you can use functions to generate these things. You can extend them. You can do all kinds of stuff. But, yeah, that's pretty cool. I'll get back to that in a second.

JASON: Got it. Great. Okay. So we've got our fields here. We're feeding in the fields what looks to be a collection of additional fields. So it's like a group block. That's always kind of a nice way to work so it's not just a stack of inputs. They're thematically associated to actually be part of the same thing.

JAMES: Exactly.

JASON: Let's see. What else should we look at?

JAMES: There's one other thing in the hero I want to look at real quick, in that file. So if you scroll down, you can see we have high impact, medium impact, and low impact. Those are the selection options. Those are the type, like I was mentioning. That's how the editor will be able to choose what type do I want. But if you remember back to the mock-ups, the low impact had no media field, right. But the high and the medium did have a media field.

JASON: Right.

JAMES: So scroll down a little bit and find that media field. Right here. You can see we have a condition that will conditionally render this field if the type is either high impact or medium impact. So if you choose low impact, this field will simply just omit itself from the admin UI.

JASON: Nice.

JAMES: Which is super cool. This feature, it pains me to admit this, but WordPress did it the best. And it's of the only CMSs with advanced custom fields that has conditional logic like this. But this is super powerful because you can build really flexible and dynamic UI for your admins so they only ever see what's relevant to them at the time.

JASON: Yeah, I mean, let's give WordPress its flowers. There's a reason it powers, what, 40% of the internet. Whatever the amount is. It's because it's really good. The reason people dislike WordPress is because they built too complicated of things on top of it. Of core of WordPress is fantastic. Advanced custom fields is potentially the most useful plug-in of my entire career.

JAMES: Agreed. Agreed. It was a huge inspiration for what we did with Payload because I've done a lot of stuff I'm really proud of with WordPress, to be honest.

JASON: Absolutely. I built my whole career on it. I did a decade of work as an agency runner, all in WordPress. I tried building my own CMS and spent all my time maintaining the dang CMS. I was like, I should just use WordPress and focus on supporting my clients instead of all this -- and you know, I did -- I was doing marketing websites. There was no reason for me to be building and maintaining my own CMS. It was just because I thought it was fun.


JASON: Remember, chat, when I talk about passionate developers causing problems, it was me. (Laughter) I have caused more problems for myself and my teams than anybody I know because I get excited about things and want to do them for the sake of doing them. And you know, sometimes you just got to use the right tool for the job and don't reinvent a wheel. But yeah, so this is such a killer feature. Because it's so -- it is so hard when you've got a CMS to train people that, like, certain fields don't always work.


JASON: Just an absolute nightmare to try to get that across.

JAMES: Nailed it. I completely agree. Like, yeah, it's been a thorn in my side for a lot of bigger projects I've used, like more modern headless CMSs where I did not use WordPress and went another modern one that lacked conditional logic. The editors are like, I have to skip over these 16 fields because they don't apply right now. I have to cognitive associate these fields apply here but not here but not here. You just hide them in Payload. It's just a function where you return a Boolean, and you're done. If you see that condition function has two arguments, the first one is underscore because we're not using it here, but the second one is sibling data. It's only the immediately adjacent fields. So the first argument is the full document. Then you can parse down whatever. But if you're deep inside of an array or deep inside of a block and you only need to look at that row of the data, then you can use the sibling data argument and look at the immediately adjacent fields, which makes it a lot easier.

JASON: Yeah, because there are reasons that you would want to do something like you have a global setting for -- actually, this wouldn't even be that. This is the individual document.

JAMES: Yep, yep. Individual document. But let's say you have a mega menu and like 13 links. You want to enable an icon for a mega menu item and it's the eighth item. You need to show and hide that field based on the eighth item check box. You have to drill down and how do you know you're in the eighth one. It's complicated, but basically, we took care of all of it for you. That's why we're pulling type from the sibling data there.

JASON: Yeah, that's nice. That is very nice. At least my conditional logic is almost always related to the document itself. And to something that's nearby. I have switched off the image toggle. I need to hide the image field. Something like that. It's almost never like, well, we checked a box in the global setting that should enable this extra thing. Sometimes you need that. But it's pretty rare.

JAMES: Absolutely. So, yeah, I think that's all we really need to look at in the hero, and we're almost done with the Payload side. Then we can jump to the Next side.

JASON: We have about ten minutes left. So why don't we hop on over, unless there was something very specific you wanted to show.

JAMES: Just the blocks. And you're right there. This will be one minute. Just scroll down a little bit in the tab there, or in the pages. Right here. You can see we've got a layout with blocks. Then we import the three different blocks we have. Those are configs that each correspond to one of the blocks we've built in our design. So you can maintain this. You can additional blocks. Just import them and pass it. And then we'll map these blocks and these field schemas to React components.

JASON: Got it. So let's hop into this. You know what, I'm just going to even skip the part where we have to download this thing. I'm going to open it up in GitHub editor.

JAMES: That's a really good idea.

JASON: These things are so dope.

JAMES: I know. I always forget about it.

JASON: Well, they don't advertise it very well. But for anybody going, what did you just do, you just have to press the period button when you're looking at a repo, and it's going to turn this on. So this is a VSCode in the browser. It's dope.

JAMES: Yes. Very cool.

JASON: But my connection is going to mess with me today. Come on. Go, go, go. You can do it.

JAMES: It'll be worth it. Yeah, I got to use this more.

JASON: You know, you say this is going to be faster than cloning it, and the universe immediately teaches you a lesson. Let's see if I can get to -- give me the content. Come on. Oh, it's activating extensions. It's turning a bunch of stuff on. So this is that first-load experience where it's got to configure based on the project settings and all that kind of stuff.

JAMES: Oh, this is just a straight-up Next site. I would expect this would be pretty fast actually.

JASON: I think they have a handful of things they got to get. Reload required. Don't you do that to me. Come on. Let's go. Go faster. There we go. Here's our stuff.

JAMES: Beautiful. All right. So I'm sure the universe is familiar with Next.js at this point. If you're not, you should be. I love Next. It's beautiful. But what we've got here, and you went right to it, so index said -- so, this is interesting. You ever had a homepage template that needs to be slashed or whatever, but then it's the same exact rendering necessary for any other page. So your homepage will render the same, quote, template as your about page. Whatever. They're both pages, and they both come from the same place in the CMS. But you need to have two different files stubbed out in Next.js for that. Here's out solution to that. So I just import from the .slug and re-export from this and then reshare the code. You see that?

JASON: Got you. Got you. Okay. So into the slug we go.

JAMES: Yeah, this is where all the meat is of the page. But it's statically rendered. So all we're doing is we're rendering out the hero and the blocks. We have components for those two things. So hero will be responsible for selecting which hero type you've decided to render. Then the blocks we pass at the array of block data, which is all fetched by GraphQL. If you scroll down, you can see Apollo client, where we're fetching a page from the query. And we're actually caching. We're using Apollo specifically here to cache data so that when we statically build our site, and if there's 300 pages, you have to blast that global data end point. You have to fetch the main menu, the footer, all those different global pieces of data you need to fetch for every single page you statically render. That's 300 hits to your API, all for the same exact data. So we've done get Apollo client, which if you command click into that, or however you do that here.

JASON: Is this going to do the thing I want? It is. Perfect.

JAMES: Almost. Still got to click on the path there.

JASON: Come on, dog. There we go. Nope. (Laughter) Here we go.

JAMES: So we basically keep it as a let on line three. If it doesn't exist, then we new it up. It will allow us to cache those global data queries so that only the first page that's statically rendered will fetch them. Then we use them from cache. Therefore, we don't blow up our CMS API. You could, but just a little optimization that I think is cool.

JASON: And I don't know if Payload CMS has rate limit, but a lot of APIs will have rate limits. It can be surprising when you're statically generating something that during your build process, you hit the rate limit and you're like, what, why? I only called one build. But each page is a request, and a fast build system is going to send off 500 requests in under a second, which you know, most APIs that weren't designed for that kind of static build will go, wait, this is wrong, and then they shut you down. Then you have to add -- then you have to add time-outs or something. It can get really challenging. So yeah, figuring better ways to complete that will help.

JAMES: Totally. We have rate limits, but it's customizable because you own your server. You can increase the rate limit, turn it off, whatever you want.

JASON: Got it.

JAMES: This is just an optimization that I think is cool. But hopping back over to that slug file there.

JASON: All right. So we've loaded our data. Here it is. We get it out. So we send in the page. Where did this page come from?

JAMES: Imported it.

JASON: Oh, got it. Okay. And then we get -- we send in the variable slug. Good.

JAMES: Then boom. Done. Fetch the data.

JASON: Beauty.

JAMES: Yeah, pretty straightforward. And then we use the data. So I guess we could look at the hero component or the blocks component. Either one.

JASON: Let's do it. So this hero component I think is going to be fun because it is -- let's see. It's going to be one of these. Let's start with the high impact.

JAMES: Yep. So not a lot of code. We always use faceless UI wherever we can. It's our homegrown set of components. I like Tailwind. I like what they're doing. I've never really used bootstrap or material UI really. I like to roll my own CSS. So this little framework here, it's not a lot of code, but it's pretty straightforward, and I don't think I needed to pull in a library for that. So I didn't. The only things that we're leveraging faceless UI for is for your break points. That's it.

JASON: Nice, nice. Cool. So we've got -- so we're setting up a gutter, which I'm assuming is your margin system that you've made. Oh, your left and right. And then we've got grid and cell. Okay. That gives us the ability to set up the -- because it's a 12-column grid.

JAMES: Correct.

JASON: Then we throw in the rich content, which we saw over here. Where are my heroes?

JAMES: Scroll up. Yep.

JASON: So we have rich content here.


JASON: Then we've got links. So these are the calls to action, I'm assuming.


JASON: So that's going to be these.


JASON: Then we've got our media.

JAMES: Exactly.

JASON: Which is here. Then if we go to low impact, it's much simpler. It doesn't have any of that media, and it's just rich text.

JAMES: Exactly. Then that index.tsx is what's responsible for determining which hero to render. So all we do is create a store of the heroes. Then render the hero that they selected. So it's real simple.

JASON: Yeah, yeah, nice and straightforward. Well, cool. The structure of this makes sense, right. You've got a CMS. The data in the CMS is structured. It's got TypeScript. It's going to give us the ability to kind of define our different blocks down to the field level, but then kind of expanding up into these more, like, comprehensive, like here's the full block. And you could probably take that a step further and compose blocks into premade layouts if you wanted templates. Then what comes out in the React app or the Next app is basically the same structure of content. Then you just kind of map a component to the layout block. Do you have any tips or tricks with the two minutes we have left for people who are building these out to help with the maintenance of as your CMS evolves, how do you keep it from breaking your components too badly?

JAMES: Number one, use TypeScript. That's huge. That's honestly saved me so much time and effort over the last two or three years. We went full in on it and never looked back, and it was huge. Be as strict as you can with your typing. Try to leverage it as much as possible. Don't use any -- you're going to sort a lot of things out on your own just by using TypeScript. But also, try to -- I wouldn't try to refactor and try to stay as dry as you can until you have the majority of the parts in place. Then you can kind of consolidate at that point. But that's a step that you should definitely do. Like deliberately do it. Set aside some time. Like, okay, we've got most of this in place. Now it's time to try to dry up some of it if we can. That will help over the long run. But don't do it too prematurely. If you do, then you're going to create heartache for yourself. But just having that mind set of try to do that at some point, that's going to help out a lot.

JASON: Gotcha. All right. So James, where should someone go if they want to dig deeper and do more?

JAMES: Well, I think we should circulate the links to those two repos. Those would be great learning resources for people if they want to take a look at those.

JASON: All right. So we'll toss those into the chat here. Then I think I can go to the repository. There it is. Drop that one.

JAMES: Then getting started with Payload is just npx create-payload-app. We have a couple videos on YouTube to check out. Get you going. Nice and easy.

JASON: Nice. All right. Make sure, everyone, go and follow James if you have more questions about Payload. If you want to ask anything, send that straight across. This episode, like every episode has been live captioned. We've had Rachel with us all day from White Coat Captioning. Thank you so much, Rachel. That's made possible through the support of our sponsors. Netlify, Nx, New Relic all kicking in to make this show more accessible to more people, which I appreciate very much. While you're checking out things on the site, make sure you go and take a look at the schedule. We've got so much good stuff coming up. It's going to be incredible. We had a switch. Mark is not able to join us. We're going to have Eli Lucas instead. We're going to look at component tests and web apps using Cypress. That's going to be super fun. We have Brian talking about the new framework Enhance. Colby Fayock is going to talk about Next.js with Cloudinary. Joyce Park, we had to reschedule this because I couldn't get my computer to work. We're going to talk about FIDO2. And if you haven't seen Shaundai's original episode, check it out. She's talking about React app performance. And Seb is coming on. We're going to talk about documentation with Docusaurus 2.0. That's just what I've had time to put on the site. There will be more. Make sure you add on Google calendar, follow on Twitch, subscribe on YouTube. All the things because it makes my little heart smile to see those numbers go up. James, thank you so much for taking some time to hang out. This has been an absolute blast. Any parting words before we go and raid? We're going to go raid Julie.

JAMES: I am excited to see you at Jamstack Conf coming up.

JASON: Yes! Please get tickets to Jamstack Conf, everyone. It is going to be so much fun. We have an in-person event, if you're in the San Francisco area or want to come. There's going to be a bunch of us there. It's going to be super fun. We have a lot of good parties. We're going to do like a puppy-petting party, if you want low key, or we have an algo rave with Dan Styles, who's been on the show before. We'll do music, and it'll be super fun. Or you can attend for free online, if you want. Virtually, we're going to have all sorts of fun stuff going there as well. So James, we'll see you at Jamstack Conf. Thank you all for hanging out. We're going to go raid Julie. See you all next time.

Closed captioning and more are made possible by our sponsors: