{"id":250,"date":"2026-01-30T09:55:35","date_gmt":"2026-01-30T09:55:35","guid":{"rendered":"https:\/\/productive.io\/engineering\/blog\/"},"modified":"2026-01-30T09:55:35","modified_gmt":"2026-01-30T09:55:35","slug":"custom-fields-give-your-customers-the-fields-they-need","status":"publish","type":"post","link":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/","title":{"rendered":"Custom Fields: Give Your Customers the Fields They Need"},"content":{"rendered":"<p   > <a href='https:\/\/productive.io\/engineering\/category\/backend\/'>Backend<\/a><\/p> &#8211; <p   > {{minutes}} min read<\/p> <h1   > Custom Fields: Give Your Customers the Fields They Need<\/h1> <a href=\"https:\/\/productive.io\/engineering\/author\/nikola-buhincek\/\"> <img  src=\"https:\/\/website-assets.productive.io\/uploads\/2024\/02\/profi-e1708437204597.jpeg\"  alt=\"\" loading=lazy \/> <\/a> <a href=\"https:\/\/productive.io\/engineering\/author\/nikola-buhincek\/\"> <p   > Nikola Buhini\u010dek<\/p><\/a> Backend Tech Lead at Productive. Pretty passionate about working on one product and taking part in decision-making. When I\u2019m not coding, you\u2019ll probably find me chilling with my friends and family.<p   > January 30, 2026<\/p> <a aria-hidden=\"false\"   href=https:\/\/www.facebook.com\/sharer.php?u=https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need target=_blank rel=\"noopener noreferrer\" > <\/a><a aria-hidden=\"false\"   href=https:\/\/twitter.com\/intent\/tweet?text=Custom%20Fields%3A%20Give%20Your%20Customers%20the%20Fields%20They%20Need&amp;url=https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need target=_blank rel=\"noopener noreferrer\" > <\/a><a aria-hidden=\"false\"   href=https:\/\/www.linkedin.com\/shareArticle?mini=true&amp;url=https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need target=_blank rel=\"noopener noreferrer\" > <\/a> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/Asset_11.png\"  alt=\"\" loading=lazy \/> <p   > Here at Productive, <strong>we\u2019re building an operating system for digital agencies<\/strong>.<\/p> <p   > But, because each agency is different (think type, size, services they offer, the way they\u2019re set up as an organization\u2026), they need customization options for their workflows. So it\u2019s pretty hard to model all those needs and use cases through a unified data model.<br><br><strong>If only there were a way to let them shape those models to their own needs.<\/strong><\/p> <img  src=\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2024\/01\/custom-fields-shape-those-models-to-your-own-needs.png\"  alt=\"\" loading=lazy \/> <p   > Let\u2019s say that one of our customers, <em>ACME digital agency<\/em> wants to keep track of their employees\u2019 nicknames and to be able to search them by that field. Other than that, they would also like to keep track of their birthdays and be able to sort them and group them by that date.<br><br>To me, as a developer, this sounds as simple as it gets\u2014add two new columns to the <em>people<\/em> table, open those attributes to be editable over the API and send them back in the response.<br>But should we do that? Should we add all kinds of fields to our models even if those fields are going to be used only by a handful of our customers?<br><br>Let me show you how we tackled this type of feature request and made a pretty generic system around it.<\/p> <h2   > <strong>What Did Our Customers Want?<\/strong><\/h2> <p   > It was pretty clear to us what our customers wanted, and that was:<\/p> <ul   > <li>to be able to <strong>add additional fields<\/strong> to some of our models (People, Projects, Tasks, \u2026)<\/li><li>to have <strong>various data types on those fields<\/strong> (text, number, or date)<\/li><li>to be able to <strong>search, sort, or even group<\/strong> by those fields<\/li><\/ul> <h2   > <strong>Our Approach<\/strong><\/h2> <h2   > <strong>The Custom Field Model<\/strong><\/h2> <p   > As we\u2019re building a RESTful <a href=\"https:\/\/developer.productive.io\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">API<\/a> that\u2019s formatted by the <a href=\"https:\/\/jsonapi.org\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">JSON:API specification<\/a> and store our data in a <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">MySQL8<\/a> relational database, a few things were pretty straightforward &#8211; we need a new model and we\u2019ll name it <strong>Custom Field<\/strong> (naming wasn\u2019t an issue here \ud83e\udd72).<br><br>The main attributes of that model should be:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/CF-5-t.png\"  alt=\"\" loading=lazy \/> <h2   > <strong>How To Store the Field Values?<\/strong><\/h2> <p   > OK, so now that we know how to define custom fields, how can we know which value someone assigned to a custom field for some object? And where to store that information?<br><br>Three possible solutions came to mind:<\/p> <p   > <strong>1. Add a limited number of <em>custom_field<\/em> columns to our models<\/strong><br><br>We can add a few custom_field columns to our models and that will work for some of our customers but there will always be others that need few extra fields. Adding numerous columns to our models surely isn\u2019t the best solution, we can do better than this \ud83d\ude05<br><br><br><strong>2. Add a join table<\/strong><br><br>As mentioned before, while relying on a relational database, a join table sounds like the go-to approach. That table would be a simple join table between the custom field and a polymorphic target (yay, Rails \ud83e\udd73). Other than those foreign keys, we would have a column to store the value.<br><br><br><strong>3. Add a single JSON column to our models<\/strong><br><br>This sounded as flexible as it gets. It would be a simple map where the key would be the custom field ID and the value would be the assigned value for that custom field.<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/CF_3_t_1.png\"  alt=\"\" loading=lazy \/> <h2   > <strong>Why We Ended Up Choosing JSON<\/strong><\/h2> <p   > The first solution was just too limited so we discarded that one immediately and focused on the remaining two solutions.<br><br>On one hand, a better design would be to have the custom field values represented by a model but on the other hand, we won\u2019t actually do much with that data. That would just be data that our users set on our objects, data that isn\u2019t important for our business logic. So a simple JSON column didn\u2019t sound bad either.<br><br>The searching and sorting aspect of this feature request was probably the most important one for us. That was supposed to work as fast as it gets, without being a burden to our performance.<br><br>That\u2019s why we implemented both solutions, tested a lot of searching\/sorting\/grouping scenarios (we\u2019ll go through that in more detail soon), and then checked the metrics.<br><br>The faster solution was the second one, the one with the JSON column, and that made sense to us. That solution doesn\u2019t use <code>JOIN<\/code> clauses in SQL since the values are written directly in the searched table and can be queried in the <code>WHERE<\/code> clause. Luckily for us, MySQL8 supports a bunch of <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/json-functions.html\" target=\"_blank\" rel=\"noreferrer noopener\">great functions to work with JSON columns<\/a> (<code>JSON_EXTRACT<\/code>, <code>JSON_UNQUOTE<\/code>, <code>JSON_CONTAINS<\/code> and others).<\/p> <h2   > <strong>Great! Now that we know how to store the custom field values too, let\u2019s dig into the coding.<\/strong><\/h2> <p   > From a development point of view, we did the following:<\/p> <ul   > <li>Added a new model, <strong>Custom Field<\/strong>, and implemented CRUD operations that can be called over the API<\/li><li>Wrote schema migrations that added a JSON column &#8211;<em>custom_fields<\/em> &#8211; to some of our models (people, projects, tasks, \u2026)<\/li><li>Opened the <em>custom_fields<\/em> attribute so it can be edited over the API<\/li><li>Wrote a generic validation that checks if all the values in the <em>custom_fields<\/em> hash have the appropriate data type<\/li><li>Added the <em>custom_fields<\/em> attribute to the API response of the appropriate models<\/li><\/ul> <p   > That was most of the work we needed to do to be able to manage custom fields in our models.<br><br>But\u2026what about the searching and sorting aspect of custom fields?<\/p> <h2   > <strong>Searching Through Custom Field Values<\/strong><\/h2> <p   > We already had a generic solution written for <a href=\"https:\/\/developer.productive.io\/index.html#header-filtering\" target=\"_blank\" rel=\"noreferrer noopener\">searching over the API<\/a>.<br><br>We have a format of sending query params for searching, like <code>filter[attribute][operation]=value<\/code>. For searching through custom fields, we wanted to keep the same format so we ended with a quite similar one &#8211;<code>filter[custom_fields][custom_field_id][operation]=value<\/code>.<br><br>We had to add an if-else statement that would handle the custom fields filtering in a different way than filtering through other attributes as the format contained one additional argument\u2014<code>custom_field_id<\/code>.<br><br>What was different in the filtering logic was that we have to load the custom field that\u2019s being filtered by and check what data type its values are. That\u2019s needed to cast the values into numbers or dates\u2014text values don\u2019t make a difference.<br><br>So the query params and its SQL query counterparts, based on custom field type, would look like this:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/03.png\"  alt=\"\" loading=lazy \/> <h2   > <strong>Sorting by Custom Field Values<\/strong><\/h2> <p   > The concept of <a href=\"https:\/\/developer.productive.io\/index.html#header-sorting\" target=\"_blank\" rel=\"noreferrer noopener\">sorting<\/a> by attributes is something we also already tackled by abstracting logic.<br><br>The only thing that changes when sorting by custom fields is that we first need to cast the values and then sort by them.<br><br>Once again, there\u2019s a small change in the format for custom fields sorters (<code>sort=custom_fields[custom_field_id]<\/code>) compared to when sorting by a standard attribute (<code>sort=attribute<\/code>). We need to handle the custom_fields sorters separately because we have to load the desired custom_field and check its type.<br><br>Then the <code>ORDER BY<\/code> statement, based on custom field types, looks like this:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/04.png\"  alt=\"\" loading=lazy \/> <h2   > <strong>Grouping by Custom Field Values<\/strong><\/h2> <p   > This was a fun one. The main point here was that you should include the custom fields as some kind of columns stated in the <code>SELECT<\/code> statement so that you could later use those columns in the <code>GROUP BY<\/code> statement.<br><br>To get the custom field in the <code>SELECT<\/code> statement, you have to create a virtual column for it. All we needed to do was to extract the values of the grouped custom field and give that virtual column an alias so that we could reference it in the <code>GROUP BY<\/code> statement. For the column alias we went with the format <code>custom_fields_{custom_field_id}<\/code>.<br><br>For a custom field with id=<em>x,<\/em> this is done as following:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/01.png\"  alt=\"\" loading=lazy \/> <p   > Once we have the virtual column defined, the grouping part gets done simply, by adding the <code>GROUP BY<\/code> statement with the earlier mentioned alias.<br><br>So in the end, you get a SQL query like:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/02.png\"  alt=\"\" loading=lazy \/> <h2   > <strong>What Our Customers Got<\/strong><\/h2> <p   > A simple way to define Custom Fields:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/cf-2.png\"  alt=\"\" loading=lazy \/> <p   > And a place to assign values to their fields:<\/p> <img  src=\"https:\/\/productive.io\/engineering\/wp-content\/uploads\/sites\/2\/2022\/11\/Screenshot-2022-11-17-at-22.12.36.png\"  alt=\"\" loading=lazy \/> <h2   > <strong>Summa Summarum<\/strong><\/h2> <p   > We made it possible for our customers to define custom fields in our data models. Also, we made it possible to search, sort and group by those fields.<br><br>It wasn&#8217;t long before we had even more requests that built upon our custom fields architecture. The fields we supported at first were okay, but now our customers wanted more field types. They wanted:<\/p> <ul   > <li>to have dropdown custom fields<\/li><li>to have relational custom fields<\/li><li>a field where the values would be objects from one of our existing data models<\/li><\/ul> <p   > But before we dig into that, let\u2019s give some time for this basics to sink in. I\u2019ll be back soon with another blog post in which I cover how we solved that new set of feature requests.<\/p> <a aria-hidden=\"false\"   href=https:\/\/www.facebook.com\/sharer.php?u=https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need target=_blank rel=\"noopener noreferrer\" > <\/a><a aria-hidden=\"false\"   href=https:\/\/twitter.com\/intent\/tweet?text=Custom%20Fields%3A%20Give%20Your%20Customers%20the%20Fields%20They%20Need&amp;url=https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need target=_blank rel=\"noopener noreferrer\" > <\/a><a aria-hidden=\"false\"   href=https:\/\/www.linkedin.com\/shareArticle?mini=true&amp;url=https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need target=_blank rel=\"noopener noreferrer\" > <\/a> <img  src=\"https:\/\/website-assets.productive.io\/uploads\/2024\/02\/profi-e1708437204597.jpeg\"  alt=\"\" loading=lazy \/> <p   > Nikola Buhini\u010dek<\/p> Backend Tech Lead at Productive. Pretty passionate about working on one product and taking part in decision-making. When I\u2019m not coding, you\u2019ll probably find me chilling with my friends and family.<a   href=\"https:\/\/productive.io\/engineering\/author\/nikola-buhincek\/\" > More From This Author <\/a> <h2   > Related articles<\/h2> <a href=\"https:\/\/productive.io\/engineering\/how-react-ruined-web-development\/\"   > <img  src=\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/BP_react-1-768x322.png\"  alt=\"\" loading=lazy \/> <p   > Engineering \u2022 Frontend<\/p> <h2   > How React Ruined Web Development<\/h2> <\/a><a href=\"https:\/\/productive.io\/engineering\/pull-requests-the-good-the-bad-and-really-not-that-ugly\/\"   > <img  src=\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/BP_pull_requests-768x322.png\"  alt=\"\" loading=lazy \/> <p   > Engineering \u2022 Workflow<\/p> <h2   > Pull Requests\u2014The Good, the Bad and Really, Not That Ugly<\/h2> <\/a> <h2   > Related jobs<\/h2> <a href=\"https:\/\/productive.io\/careers\/open-job-application\/\"  > <p  > Open Job Application<\/p><p  > <\/p> <\/a>","protected":false},"excerpt":{"rendered":"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.","protected":false},"author":40,"featured_media":315,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"es_utils_meta_schema":"","footnotes":""},"categories":[11,7],"tags":[],"class_list":["post-250","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-backend","category-engineering"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Custom Fields: Give Your Customers the Fields They Need - Building Productive<\/title>\n<meta name=\"description\" content=\"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Custom Fields: Give Your Customers the Fields They Need\" \/>\n<meta property=\"og:description\" content=\"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\" \/>\n<meta property=\"og:site_name\" content=\"Building Productive\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-30T09:55:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1901\" \/>\n\t<meta property=\"og:image:height\" content=\"797\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Nikola Buhini\u010dek\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nikola Buhini\u010dek\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\"},\"author\":{\"name\":\"Nikola Buhini\u010dek\",\"@id\":\"https:\/\/productive.io\/engineering\/#\/schema\/person\/b8aea92d17640ade1fc1230b0812ae29\"},\"headline\":\"Custom Fields: Give Your Customers the Fields They Need\",\"datePublished\":\"2026-01-30T09:55:35+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\"},\"wordCount\":9,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png\",\"articleSection\":[\"Backend\",\"Engineering\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\",\"url\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\",\"name\":\"Custom Fields: Give Your Customers the Fields They Need - Building Productive\",\"isPartOf\":{\"@id\":\"https:\/\/productive.io\/engineering\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png\",\"datePublished\":\"2026-01-30T09:55:35+00:00\",\"author\":{\"@id\":\"https:\/\/productive.io\/engineering\/#\/schema\/person\/b8aea92d17640ade1fc1230b0812ae29\"},\"description\":\"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.\",\"breadcrumb\":{\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage\",\"url\":\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png\",\"contentUrl\":\"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png\",\"width\":1901,\"height\":797},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/productive.io\/engineering\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Custom Fields: Give Your Customers the Fields They Need\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/productive.io\/engineering\/#website\",\"url\":\"https:\/\/productive.io\/engineering\/\",\"name\":\"Building Productive\",\"description\":\"Just another Productive Sites site\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/productive.io\/engineering\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/productive.io\/engineering\/#\/schema\/person\/b8aea92d17640ade1fc1230b0812ae29\",\"name\":\"Nikola Buhini\u010dek\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/2687fe62ebca4b36f13407f15bc76ff55d23d54ec9f86877ececbfc80ada7b6e?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2687fe62ebca4b36f13407f15bc76ff55d23d54ec9f86877ececbfc80ada7b6e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2687fe62ebca4b36f13407f15bc76ff55d23d54ec9f86877ececbfc80ada7b6e?s=96&d=mm&r=g\",\"caption\":\"Nikola Buhini\u010dek\"},\"url\":\"https:\/\/productive.io\/engineering\/author\/nikola-buhincek\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Custom Fields: Give Your Customers the Fields They Need - Building Productive","description":"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/","og_locale":"en_US","og_type":"article","og_title":"Custom Fields: Give Your Customers the Fields They Need","og_description":"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.","og_url":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/","og_site_name":"Building Productive","article_published_time":"2026-01-30T09:55:35+00:00","og_image":[{"width":1901,"height":797,"url":"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png","type":"image\/png"}],"author":"Nikola Buhini\u010dek","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Nikola Buhini\u010dek"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#article","isPartOf":{"@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/"},"author":{"name":"Nikola Buhini\u010dek","@id":"https:\/\/productive.io\/engineering\/#\/schema\/person\/b8aea92d17640ade1fc1230b0812ae29"},"headline":"Custom Fields: Give Your Customers the Fields They Need","datePublished":"2026-01-30T09:55:35+00:00","mainEntityOfPage":{"@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/"},"wordCount":9,"commentCount":0,"image":{"@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage"},"thumbnailUrl":"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png","articleSection":["Backend","Engineering"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/","url":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/","name":"Custom Fields: Give Your Customers the Fields They Need - Building Productive","isPartOf":{"@id":"https:\/\/productive.io\/engineering\/#website"},"primaryImageOfPage":{"@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage"},"image":{"@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage"},"thumbnailUrl":"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png","datePublished":"2026-01-30T09:55:35+00:00","author":{"@id":"https:\/\/productive.io\/engineering\/#\/schema\/person\/b8aea92d17640ade1fc1230b0812ae29"},"description":"Here at Productive, we\u2019re building an operating system for digital agencies. Because each agency is different, they need customization options for their workflows.","breadcrumb":{"@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#primaryimage","url":"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png","contentUrl":"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png","width":1901,"height":797},{"@type":"BreadcrumbList","@id":"https:\/\/productive.io\/engineering\/custom-fields-give-your-customers-the-fields-they-need\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/productive.io\/engineering\/"},{"@type":"ListItem","position":2,"name":"Custom Fields: Give Your Customers the Fields They Need"}]},{"@type":"WebSite","@id":"https:\/\/productive.io\/engineering\/#website","url":"https:\/\/productive.io\/engineering\/","name":"Building Productive","description":"Just another Productive Sites site","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/productive.io\/engineering\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/productive.io\/engineering\/#\/schema\/person\/b8aea92d17640ade1fc1230b0812ae29","name":"Nikola Buhini\u010dek","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/2687fe62ebca4b36f13407f15bc76ff55d23d54ec9f86877ececbfc80ada7b6e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/2687fe62ebca4b36f13407f15bc76ff55d23d54ec9f86877ececbfc80ada7b6e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2687fe62ebca4b36f13407f15bc76ff55d23d54ec9f86877ececbfc80ada7b6e?s=96&d=mm&r=g","caption":"Nikola Buhini\u010dek"},"url":"https:\/\/productive.io\/engineering\/author\/nikola-buhincek\/"}]}},"featured_image":"https:\/\/website-assets.productive.io\/uploads\/sites\/2\/2022\/11\/Asset_11.png","category":"Backend","_links":{"self":[{"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/posts\/250","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/users\/40"}],"replies":[{"embeddable":true,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/comments?post=250"}],"version-history":[{"count":10,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/posts\/250\/revisions"}],"predecessor-version":[{"id":990,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/posts\/250\/revisions\/990"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/media\/315"}],"wp:attachment":[{"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/media?parent=250"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/categories?post=250"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/productive.io\/engineering\/wp-json\/wp\/v2\/tags?post=250"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}