{"id":32321,"date":"2026-07-24T11:20:50","date_gmt":"2026-07-24T09:20:50","guid":{"rendered":"https:\/\/contabo.com\/blog\/?p=32321"},"modified":"2026-07-24T11:28:53","modified_gmt":"2026-07-24T09:28:53","slug":"nodejs-postgresql-vps-sizing","status":"publish","type":"post","link":"https:\/\/contabo.com\/blog\/nodejs-postgresql-vps-sizing\/","title":{"rendered":"How Much RAM and CPU Does a VPS Need for Node.js + PostgreSQL?"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">For a typical production Node.js app with PostgreSQL on one VPS: 2 vCPU \/ 4 GB RAM \/ NVMe SSD. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s the baseline. The right size below or above it depends on where your project actually sits \u2014 a hobby project and a database serving real production traffic have very different floors, and the table below maps both.<\/p>\n\n\n\n<div class=\"cnt-vps-sizing\" role=\"region\" aria-label=\"Node.js + PostgreSQL VPS sizing tiers\">\n  <p class=\"cnt-vps-sizing__lead\">\n    <strong>Quick answer:<\/strong> a typical production Node.js + PostgreSQL app needs\n    <strong>2 vCPU \/ 4 GB RAM \/ NVMe SSD<\/strong> as a baseline \u2014 scale up or down using the tiers below.\n  <\/p>\n\n  <table class=\"cnt-vps-sizing__table\">\n    <caption class=\"cnt-vps-sizing__caption\">\n      VPS sizing tiers for Node.js + PostgreSQL, by workload stage\n    <\/caption>\n    <thead>\n      <tr>\n        <th scope=\"col\">Tier<\/th>\n        <th scope=\"col\">vCPU<\/th>\n        <th scope=\"col\">RAM<\/th>\n        <th scope=\"col\">Storage<\/th>\n      <\/tr>\n    <\/thead>\n    <tbody>\n      <tr>\n        <th scope=\"row\">Hobby \/ MVP<\/th>\n        <td>1 vCPU<\/td>\n        <td>1\u20132 GB<\/td>\n        <td>SSD<\/td>\n      <\/tr>\n      <tr class=\"cnt-vps-sizing__row--highlight\">\n        <th scope=\"row\">\n          Production baseline\n          <span class=\"cnt-vps-sizing__badge\">Recommended<\/span>\n        <\/th>\n        <td>2 vCPU<\/td>\n        <td>4 GB<\/td>\n        <td>NVMe<\/td>\n      <\/tr>\n      <tr>\n        <th scope=\"row\">Medium<\/th>\n        <td>2\u20134 vCPU<\/td>\n        <td>4\u20138 GB<\/td>\n        <td>NVMe<\/td>\n      <\/tr>\n      <tr>\n        <th scope=\"row\">High<\/th>\n        <td>4+ vCPU<\/td>\n        <td>8\u201316 GB<\/td>\n        <td>NVMe<\/td>\n      <\/tr>\n    <\/tbody>\n  <\/table>\n<\/div>\n\n<style>\n.cnt-vps-sizing {\n  margin: 1.5em 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n}\n.cnt-vps-sizing__lead {\n  font-size: 1.02em;\n  line-height: 1.6;\n  color: #2b2b2b;\n  background: #f0f4fa;\n  border-left: 4px solid #365F91;\n  padding: 0.85em 1.1em;\n  border-radius: 4px;\n  margin: 0 0 1em 0;\n}\n.cnt-vps-sizing__table {\n  width: 100%;\n  border-collapse: collapse;\n  font-size: 0.96em;\n  background: #fff;\n  border-radius: 6px;\n  overflow: hidden;\n  box-shadow: 0 1px 3px rgba(0,0,0,0.08);\n}\n.cnt-vps-sizing__caption {\n  text-align: left;\n  font-weight: 600;\n  color: #365F91;\n  padding: 0 0 0.6em 0;\n  font-size: 0.95em;\n}\n.cnt-vps-sizing__table thead th {\n  background: #365F91;\n  color: #fff;\n  font-weight: 600;\n  text-align: left;\n  padding: 0.7em 1em;\n}\n.cnt-vps-sizing__table tbody th,\n.cnt-vps-sizing__table tbody td {\n  padding: 0.65em 1em;\n  border-bottom: 1px solid #e3e8f0;\n  text-align: left;\n  color: #333;\n}\n.cnt-vps-sizing__table tbody th {\n  font-weight: 600;\n  color: #2b2b2b;\n}\n.cnt-vps-sizing__table tbody tr:last-child th,\n.cnt-vps-sizing__table tbody tr:last-child td {\n  border-bottom: none;\n}\n.cnt-vps-sizing__table tbody tr:nth-child(even) {\n  background: #f7f9fc;\n}\n.cnt-vps-sizing__row--highlight {\n  background: #eaf1fb !important;\n}\n.cnt-vps-sizing__badge {\n  display: inline-block;\n  margin-left: 0.5em;\n  padding: 0.15em 0.55em;\n  font-size: 0.7em;\n  font-weight: 700;\n  letter-spacing: 0.02em;\n  color: #fff;\n  background: #4F81BD;\n  border-radius: 999px;\n  vertical-align: middle;\n}\n@media (max-width: 600px) {\n  .cnt-vps-sizing__table { display: block; overflow-x: auto; white-space: nowrap; }\n}\n<\/style>\n\n\n\n<h2 id=\"h-memory-budget-breakdown-where-the-ram-actually-goes\" class=\"wp-block-heading\">Memory Budget Breakdown: Where the RAM Actually Goes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The 4 GB production baseline isn&#8217;t one number \u2014 it&#8217;s three components stacked on top of each other, and knowing the split is what lets you size up or down with confidence instead of guessing.<\/p>\n\n\n\n<div class=\"cnt-mem-budget\" role=\"region\" aria-label=\"Node.js + PostgreSQL memory budget breakdown\">\n  <p class=\"cnt-mem-budget__lead\">\n    <strong>Quick answer:<\/strong> the 4 GB production baseline splits roughly into\n    OS overhead, Node.js&#8217;s V8 heap, and PostgreSQL&#8217;s <code>shared_buffers<\/code> \u2014 no single\n    component owns the full budget.\n  <\/p>\n\n  <table class=\"cnt-mem-budget__table\">\n    <caption class=\"cnt-mem-budget__caption\">\n      Memory budget breakdown for a 4 GB Node.js + PostgreSQL VPS\n    <\/caption>\n    <thead>\n      <tr>\n        <th scope=\"col\">Component<\/th>\n        <th scope=\"col\">Typical footprint<\/th>\n        <th scope=\"col\">Notes<\/th>\n      <\/tr>\n    <\/thead>\n    <tbody>\n      <tr>\n        <th scope=\"row\">OS baseline<\/th>\n        <td>~500 MB&nbsp;\u2013&nbsp;1 GB<\/td>\n        <td>A minimal Ubuntu server plus SSH, systemd, and background services.<\/td>\n      <\/tr>\n      <tr>\n        <th scope=\"row\">Node.js \/ V8 heap<\/th>\n        <td>~1\u20132 GB<span class=\"cnt-mem-budget__note\">(varies)<\/span><\/td>\n        <td>\n          Modern Node.js (v20+) is container-aware and scales heap to roughly 50% of available\n          memory, capping around 2 GiB internally \u2014 it does not use a fixed default regardless of\n          system RAM. Set <code>--max-old-space-size<\/code> explicitly for predictable behavior on\n          a constrained VPS rather than relying on the automatic default.\n        <\/td>\n      <\/tr>\n      <tr>\n        <th scope=\"row\">PostgreSQL <code>shared_buffers<\/code><\/th>\n        <td>~25% of total RAM<\/td>\n        <td>\n          PostgreSQL&#8217;s own documentation recommends starting at 25% of system RAM, with\n          diminishing returns above roughly 40% \u2014 on a 4 GB VPS, that&#8217;s about 1 GB.\n        <\/td>\n      <\/tr>\n    <\/tbody>\n  <\/table>\n<\/div>\n\n<style>\n.cnt-mem-budget {\n  margin: 1.5em 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n}\n.cnt-mem-budget__lead {\n  font-size: 1.02em;\n  line-height: 1.6;\n  color: #2b2b2b;\n  background: #f0f4fa;\n  border-left: 4px solid #4F81BD;\n  padding: 0.85em 1.1em;\n  border-radius: 4px;\n  margin: 0 0 1em 0;\n}\n.cnt-mem-budget__table {\n  width: 100%;\n  border-collapse: collapse;\n  font-size: 0.95em;\n  background: #fff;\n  border-radius: 6px;\n  overflow: hidden;\n  box-shadow: 0 1px 3px rgba(0,0,0,0.08);\n}\n.cnt-mem-budget__caption {\n  text-align: left;\n  font-weight: 600;\n  color: #4F81BD;\n  padding: 0 0 0.6em 0;\n  font-size: 0.95em;\n}\n.cnt-mem-budget__table thead th {\n  background: #4F81BD;\n  color: #fff;\n  font-weight: 600;\n  text-align: left;\n  padding: 0.7em 1em;\n}\n.cnt-mem-budget__table tbody th,\n.cnt-mem-budget__table tbody td {\n  padding: 0.7em 1em;\n  border-bottom: 1px solid #e3e8f0;\n  text-align: left;\n  vertical-align: top;\n  color: #333;\n  line-height: 1.55;\n}\n.cnt-mem-budget__table tbody th {\n  font-weight: 600;\n  color: #2b2b2b;\n  white-space: nowrap;\n}\n.cnt-mem-budget__table tbody tr:last-child th,\n.cnt-mem-budget__table tbody tr:last-child td {\n  border-bottom: none;\n}\n.cnt-mem-budget__table tbody tr:nth-child(even) {\n  background: #f7f9fc;\n}\n.cnt-mem-budget__table code {\n  background: #eef1f6;\n  color: #365F91;\n  padding: 0.1em 0.4em;\n  border-radius: 3px;\n  font-size: 0.92em;\n}\n.cnt-mem-budget__note {\n  display: block;\n  font-size: 0.82em;\n  color: #777;\n  margin-top: 0.15em;\n}\n@media (max-width: 600px) {\n  .cnt-mem-budget__table thead { display: none; }\n  .cnt-mem-budget__table, .cnt-mem-budget__table tbody, .cnt-mem-budget__table tr, .cnt-mem-budget__table td, .cnt-mem-budget__table th {\n    display: block;\n    width: 100%;\n  }\n  .cnt-mem-budget__table tbody tr { border-bottom: 2px solid #e3e8f0; padding: 0.5em 0; }\n  .cnt-mem-budget__table tbody th { white-space: normal; padding-bottom: 0.2em; }\n}\n<\/style>\n\n\n\n<p class=\"wp-block-paragraph\">Add those up on a 4 GB VPS and you&#8217;re already close to the ceiling once the OS, Node&#8217;s heap, and Postgres&#8217;s shared buffers are all accounted for \u2014 which is exactly why the Production baseline tier assumes moderate, not heavy, concurrent load. Push past that with real traffic and the Medium or High tiers exist for a reason.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">When to Split the Database onto Its Own VPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The app and the database compete for the same CPU and RAM as long as they share one server. That&#8217;s fine at low-to-moderate traffic, but it stops being fine once either of these shows up:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>shared_buffers plus Node&#8217;s heap together leave under roughly 20% RAM headroom for the OS and connection overhead \u2014 the server is running structurally tight, not just busy.<\/li>\n\n\n\n<li>Database I\/O and app request handling visibly contend under load \u2014 check with vmstat or iostat during peak traffic rather than guessing from CPU percentage alone.<\/li>\n\n\n\n<li>You&#8217;re past the Medium tier&#8217;s 4-8 GB range and still seeing contention \u2014 at that point, isolating Postgres onto its own VPS is usually cheaper than continuing to scale one combined server up.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Split on the actual symptom, not a fixed schedule \u2014 a low-traffic app can live comfortably on one combined VPS well past the Production baseline tier if it never shows these signs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Mapping Each Tier to a Concrete Contabo Cloud VPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Contabo&#8217;s smallest Cloud VPS plan already starts above the Hobby\/MVP and Production baseline tiers \u2014 there&#8217;s no smaller product to map those two to, so both land on the same entry-level plan:<\/p>\n\n\n\n<div class=\"cnt-vps-mapping\" role=\"region\" aria-label=\"Contabo Cloud VPS product mapping by tier\">\n  <p class=\"cnt-vps-mapping__lead\">\n    <strong>Quick answer:<\/strong> Contabo&#8217;s entry-level Cloud VPS 4 (4 vCPU \/ 8 GB) already\n    covers both the Hobby\/MVP and Production baseline tiers \u2014 you only need to move up for\n    Medium or High workloads.\n  <\/p>\n\n  <table class=\"cnt-vps-mapping__table\">\n    <caption class=\"cnt-vps-mapping__caption\">\n      Node.js + PostgreSQL sizing tiers mapped to Contabo Cloud VPS plans\n    <\/caption>\n    <thead>\n      <tr>\n        <th scope=\"col\">Tier<\/th>\n        <th scope=\"col\">Spec<\/th>\n        <th scope=\"col\">Contabo product<\/th>\n        <th scope=\"col\">Notes<\/th>\n      <\/tr>\n    <\/thead>\n    <tbody>\n      <tr>\n        <th scope=\"row\">Hobby \/ MVP<\/th>\n        <td>1 vCPU \/ 1\u20132 GB<\/td>\n        <td><span class=\"cnt-vps-mapping__plan\">Cloud VPS 4<\/span><span class=\"cnt-vps-mapping__spec\">(4 vCPU \/ 8 GB)<\/span><\/td>\n        <td>Exceeds this tier&#8217;s requirements \u2014 Contabo&#8217;s entry plan starts above hobby-level specs.<\/td>\n      <\/tr>\n      <tr class=\"cnt-vps-mapping__row--highlight\">\n        <th scope=\"row\">\n          Production baseline\n          <span class=\"cnt-vps-mapping__badge\">Recommended start<\/span>\n        <\/th>\n        <td>2 vCPU \/ 4 GB \/ NVMe<\/td>\n        <td><span class=\"cnt-vps-mapping__plan\">Cloud VPS 4<\/span><span class=\"cnt-vps-mapping__spec\">(4 vCPU \/ 8 GB)<\/span><\/td>\n        <td>Same entry plan comfortably covers the production baseline with headroom to spare.<\/td>\n      <\/tr>\n      <tr>\n        <th scope=\"row\">Medium<\/th>\n        <td>2\u20134 vCPU \/ 4\u20138 GB<\/td>\n        <td><span class=\"cnt-vps-mapping__plan\">Cloud VPS 4\u20136<\/span><\/td>\n        <td>Cloud VPS 6 adds headroom if the app and DB are both under real, sustained load.<\/td>\n      <\/tr>\n      <tr>\n        <th scope=\"row\">High<\/th>\n        <td>4+ vCPU \/ 8\u201316 GB<\/td>\n        <td><span class=\"cnt-vps-mapping__plan\">Cloud VPS 6\u20138<\/span><\/td>\n        <td>Cloud VPS 8 is the point to consider splitting Postgres onto its own instance instead of scaling further.<\/td>\n      <\/tr>\n    <\/tbody>\n  <\/table>\n\n  <p class=\"cnt-vps-mapping__footnote\">\n    Plan names and specs current as of publication \u2014 verify current pricing and configurations on\n    <a href=\"https:\/\/contabo.com\/en\/vps\/\" rel=\"noopener\">contabo.com<\/a>.\n  <\/p>\n<\/div>\n\n<style>\n.cnt-vps-mapping {\n  margin: 1.5em 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n}\n.cnt-vps-mapping__lead {\n  font-size: 1.02em;\n  line-height: 1.6;\n  color: #2b2b2b;\n  background: #f0f4fa;\n  border-left: 4px solid #365F91;\n  padding: 0.85em 1.1em;\n  border-radius: 4px;\n  margin: 0 0 1em 0;\n}\n.cnt-vps-mapping__table {\n  width: 100%;\n  border-collapse: collapse;\n  font-size: 0.95em;\n  background: #fff;\n  border-radius: 6px;\n  overflow: hidden;\n  box-shadow: 0 1px 3px rgba(0,0,0,0.08);\n}\n.cnt-vps-mapping__caption {\n  text-align: left;\n  font-weight: 600;\n  color: #365F91;\n  padding: 0 0 0.6em 0;\n  font-size: 0.95em;\n}\n.cnt-vps-mapping__table thead th {\n  background: #365F91;\n  color: #fff;\n  font-weight: 600;\n  text-align: left;\n  padding: 0.7em 1em;\n}\n.cnt-vps-mapping__table tbody th,\n.cnt-vps-mapping__table tbody td {\n  padding: 0.7em 1em;\n  border-bottom: 1px solid #e3e8f0;\n  text-align: left;\n  vertical-align: top;\n  color: #333;\n  line-height: 1.55;\n}\n.cnt-vps-mapping__table tbody th {\n  font-weight: 600;\n  color: #2b2b2b;\n  white-space: nowrap;\n}\n.cnt-vps-mapping__table tbody tr:last-child th,\n.cnt-vps-mapping__table tbody tr:last-child td {\n  border-bottom: none;\n}\n.cnt-vps-mapping__table tbody tr:nth-child(even) {\n  background: #f7f9fc;\n}\n.cnt-vps-mapping__row--highlight {\n  background: #eaf1fb !important;\n}\n.cnt-vps-mapping__plan {\n  display: inline-block;\n  font-weight: 600;\n  color: #365F91;\n}\n.cnt-vps-mapping__spec {\n  display: block;\n  font-size: 0.82em;\n  color: #777;\n  margin-top: 0.1em;\n}\n.cnt-vps-mapping__badge {\n  display: inline-block;\n  margin-left: 0.5em;\n  padding: 0.15em 0.55em;\n  font-size: 0.7em;\n  font-weight: 700;\n  letter-spacing: 0.02em;\n  color: #fff;\n  background: #4F81BD;\n  border-radius: 999px;\n  vertical-align: middle;\n  white-space: nowrap;\n}\n.cnt-vps-mapping__footnote {\n  font-size: 0.82em;\n  color: #888;\n  margin-top: 0.6em;\n}\n@media (max-width: 600px) {\n  .cnt-vps-mapping__table thead { display: none; }\n  .cnt-vps-mapping__table, .cnt-vps-mapping__table tbody, .cnt-vps-mapping__table tr, .cnt-vps-mapping__table td, .cnt-vps-mapping__table th {\n    display: block;\n    width: 100%;\n  }\n  .cnt-vps-mapping__table tbody tr { border-bottom: 2px solid #e3e8f0; padding: 0.5em 0; }\n  .cnt-vps-mapping__table tbody th { white-space: normal; padding-bottom: 0.2em; }\n}\n<\/style>\n\n\n\n<h2 id=\"h-faq-node-js-postgresql-vps-sizing\" class=\"wp-block-heading\">FAQ: Node.js + PostgreSQL VPS Sizing<\/h2>\n\n\n\n<div class=\"schema-faq wp-block-yoast-faq-block\"><div class=\"schema-faq-section\" id=\"faq-question-1784884315039\"><strong class=\"schema-faq-question\">How much RAM does Node.js need on a VPS?<\/strong> <p class=\"schema-faq-answer\">Modern Node.js (v20+) scales its heap to roughly half of available system or container memory, capping around 2 GiB internally by default \u2014 it isn&#8217;t a fixed amount regardless of RAM. On a constrained VPS, set &#8211;max-old-space-size explicitly rather than relying on the automatic default, so Node&#8217;s memory use stays predictable alongside PostgreSQL.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1784884325932\"><strong class=\"schema-faq-question\">How much RAM should I give PostgreSQL&#8217;s shared_buffers?<\/strong> <p class=\"schema-faq-answer\">PostgreSQL&#8217;s own documentation recommends starting at 25% of total system RAM, with values above roughly 40% showing diminishing returns since the OS page cache handles the rest. On a 4 GB VPS running both Node.js and PostgreSQL, that&#8217;s about 1 GB for shared_buffers.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1784884336968\"><strong class=\"schema-faq-question\">When should I move PostgreSQL to its own server?<\/strong> <p class=\"schema-faq-answer\">Move it once shared_buffers and Node&#8217;s heap together leave under about 20% RAM headroom, or once vmstat\/iostat show real contention between database I\/O and app request handling under load \u2014 not on a fixed traffic number. Below that point, one combined VPS is usually simpler and cheaper than managing two.<\/p> <\/div> <\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Further Reading<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/contabo.com\/blog\/postgresql-on-ubuntu\/\">Install PostgreSQL on Ubuntu and Set Up pgAdmin Step by Step<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/contabo.com\/blog\/postgresql-hosting\/\">How To Host PostgreSQL Applications<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>For a typical production Node.js app with PostgreSQL on one VPS: 2 vCPU \/ 4 GB RAM \/ NVMe SSD. That&#8217;s the baseline. The right size below or above it depends on where your project actually sits \u2014 a hobby project and a database serving real production traffic have very different floors, and the table [&hellip;]<\/p>\n","protected":false},"author":78,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_uag_custom_page_level_css":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[4708],"tags":[],"ppma_author":[4285],"class_list":["post-32321","post","type-post","status-publish","format-standard","hentry","category-decision-guide"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"Jie Guo","author_link":"https:\/\/contabo.com\/blog\/author\/jieguo\/"},"uagb_comment_info":0,"uagb_excerpt":"For a typical production Node.js app with PostgreSQL on one VPS: 2 vCPU \/ 4 GB RAM \/ NVMe SSD. That&#8217;s the baseline. The right size below or above it depends on where your project actually sits \u2014 a hobby project and a database serving real production traffic have very different floors, and the table&hellip;","authors":[{"term_id":4285,"user_id":78,"is_guest":0,"slug":"jieguo","display_name":"Jie Guo","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/4e0d981b06988d6d456834e9d55bc9e713e918fa8444325543d14f448154106b?s=96&d=mm&r=g","author_category":"","user_url":"","last_name":"Guo","first_name":"Jie","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/32321","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/users\/78"}],"replies":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/comments?post=32321"}],"version-history":[{"count":3,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/32321\/revisions"}],"predecessor-version":[{"id":32325,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/32321\/revisions\/32325"}],"wp:attachment":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/media?parent=32321"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/categories?post=32321"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/tags?post=32321"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=32321"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}