TL;DR: AI-generated code can save time, but missing dependencies, outdated APIs, and incomplete component configuration often lead to manual fixes. Learn how Syncfusion Agent Skills and MCP Server help AI coding assistants generate more reliable code and provide instant access to the latest documentation without leaving your editor.
As AI developer tools become part of everyday development, improving the accuracy of generated code has become just as important as generating it quickly.
AI coding assistants can generate a form, dashboard, or data grid in seconds. The initial results often look impressive, but developers quickly discover that generating code is only part of the job.
When working with a component library such as Syncfusion, small implementation details matter. Missing imports, incorrect configuration, outdated APIs, or overlooked dependencies can turn a seemingly complete solution into a debugging session.
This is especially true when building applications with feature-rich UI components. An AI coding assistant might know how to create a grid, chart, or scheduler, but it doesn’t always know the recommended way to implement those components within a specific ecosystem.
To help bridge that gap, Syncfusion provides two AI coding assistant tools:
Together, they help reduce manual fixes and make AI-assisted development more reliable.
Modern AI coding assistants are excellent at understanding programming concepts and generating working code. However, component libraries introduce an additional layer of complexity that generic AI models don’t always have access to.
When generating code for a UI component, the assistant may need to understand:
Without that context, generated code can be incomplete or based on outdated examples.
For example, imagine prompting an AI assistant to:
Create a Syncfusion DataGrid with paging, sorting, filtering, and Excel export enabled.
The generated code may render successfully, but developers often encounter issues such as:
The challenge isn’t that the AI can’t build a grid. The challenge is ensuring it builds a Syncfusion Grid using the recommended implementation approach.
That’s the problem the Syncfusion AI coding assistant tools aim to solve.
Agent Skills are installable project-level guidance packages centered around SKILL.md instructions that AI coding assistants can use during development.
Each skill captures the recommended implementation patterns for a Syncfusion component, including:
Whenever your AI coding assistant is about to generate or modify Syncfusion code, it consults the relevant skill and follows those patterns.
The result is code that is more likely to follow established Syncfusion patterns, including the appropriate modules, feature configuration, theming guidance, and current recommended APIs. It’s especially handy for teams that want every developer, and every prompt, to stay on the same page by default.
For example, when asked to create a Syncfusion DataGrid with sorting and filtering enabled, an AI coding assistant using Agent Skills automatically includes the required modules and feature configuration instead of generating incomplete boilerplate code.
Even with implementation guidance, developers regularly run into questions that require up-to-date information.
They might need to:
This is where MCP Server becomes valuable.
The MCP Server allows AI coding assistants to retrieve information directly from Syncfusion documentation through the #search_docs tool.
Rather than relying entirely on model training data, your assistant can query current documentation and return relevant guidance while you’re working in your editor.
For example, if you’re configuring Excel export for a Grid component, the assistant can pull the latest implementation guidance from the documentation instead of relying on potentially outdated examples.
It runs locally and works in any MCP-compatible editor: VS Code, Syncfusion Code Studio, Cursor, JetBrains, and more. It also works across the full range of components and SDKs available in Syncfusion Essential Studio.
This helps reduce context switching and minimizes the need to manually search through documentation while developing.
Important note: For active Syncfusion users, access is unlimited and privacy-first: your requests are not used for model training.
Consider a developer building an internal reporting dashboard that includes:
An AI coding assistant can generate much of the initial implementation quickly. However, issues often appear during integration:
In this scenario:
Instead of switching between generated code, documentation pages, and troubleshooting articles, developers can stay focused on building features.
Not sure where to begin? Here’s a quick way to match each tool to what you’re doing.
| Tool | Best for | When to use it |
| Agent Skills | Generating Syncfusion code correctly. | Day-to-day coding assistance. |
| MCP Server | Retrieving product documentation. | Research and troubleshooting. |
Each tool solves a different problem.
Agent Skills improve code generation by giving AI assistants implementation guidance. MCP Server complements that by providing access to Syncfusion’s documentation and reference material whenever additional context is needed.
A typical development process might look like this:
The result is a development experience with fewer interruptions, fewer manual corrections, and greater confidence in the generated output.
Each tool is installed separately, so you can pick the one that matches your task and add the others whenever you need them.
Here’s how to set up each one.
Agent Skills help your assistant generate code that follows Syncfusion’s recommended patterns and best practices. They work across the full range of Syncfusion components and SDKs, providing focused guidance for controls such as Grid, Scheduler, Charts, and many others. Skills are installed at the project level, making them easy to commit to source control and share across your team.
For React projects, you can install the complete set of skills with a single command:
npx skills add syncfusion/react-ui-components-skills -y
After installation, simply describe what you want to build in natural language, and your AI coding assistant will generate code using the appropriate Syncfusion components, APIs, and implementation patterns.

Agent Skills support multiple frameworks, AI coding assistants, and development environments. For the latest list of supported platforms, installation options, and available skill packages, see the Agent Skills page.
The Syncfusion MCP Server connects your AI coding assistant directly to Syncfusion’s current documentation, API references, code examples, release updates, and troubleshooting resources. Instead of relying on training data or outdated examples, your assistant can retrieve authoritative answers directly from Syncfusion documentation during development.
For React projects, add the MCP Server to your editor’s MCP configuration. In VS Code, for example, add the following to the .vscode/mcp.json file.
{
"servers": {
"sf-react-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@syncfusion/react-mcp@latest"],
"env": {
"Syncfusion_API_Key": "YOUR_API_KEY"
}
}
}
}
With the server configured, your assistant can search documentation, look up APIs, discover newly released features, and resolve implementation questions without leaving the editor.

The MCP Server is available for multiple frameworks and integrates with a variety of AI-powered development tools and editors. For the latest list of supported platforms, configuration options, and setup instructions, see the MCP Server page.
Note: Always review AI-generated code for accuracy, security, performance implications, accessibility requirements, and compliance with your app’s requirements before production use.
Use AI agents to create implementation plans, generate production-ready code, automate repetitive tasks, and improve code quality across your projects.
Discover Code StudioWhether you’re generating Syncfusion component code or looking up the latest APIs, documentation, and code examples, Agent Skills and MCP Server can help reduce manual fixes and improve the quality of AI-generated output.
Use Agent Skills to guide code generation with recommended implementation patterns, and MCP Server to retrieve accurate technical information when you need it. Together, they help developers spend less time troubleshooting and more time building features.
Ready to try them? Explore Agent Skills and MCP Server today. If you’re new to Syncfusion, start your 30-day free trial and experience a more reliable AI-assisted development process.
If you have questions, reach out through our support forum, support portal, or feedback portal. We’re always happy to assist you!
MySQL and PostgreSQL both store spatial and geometric data, but they take fundamentally different approaches. While MySQL bakes spatial support directly into its engine, PostgreSQL separates two ecosystems: native geometric types (built-in, flat-plane, non-geographic), and PostGIS (a full GIS extension with coordinate systems, projections, and hundreds of spatial functions).
For most real-world location-aware applications — GPS tracking, geofencing, distance queries — PostGIS is the more powerful option, though MySQL 8.0 closed the gap considerably for common use cases. This guide compares their architectures, data types, indexing strategies, spatial functions, and what to watch out for if you’re migrating between them.
Every time you open Google Maps, request an Uber, track a delivery package, search for nearby restaurants, or see weather activity displayed on a map, spatial data is working behind the scenes. This is because modern applications no longer deal with just text, numbers, and dates – they increasingly need to understand location, distance, boundaries, routes and geographic relationships as well.
For example, a food delivery app needs to determine which rider is closest to a customer, and a logistics company may need to optimize delivery routes across multiple cities. Traditional data types can’t handle these kinds of operations efficiently, which is where spatial and geometric data types come in.
Both MySQL and PostgreSQL provide support for storing and querying geometric and geographic data, but they approach the problem very differently. MySQL includes spatial functionality directly within its engine, while PostgreSQL splits its capabilities between native geometric data types and the far more advanced PostGIS extension.
MySQL and PostgreSQL both support concepts like points, polygons, lines, and spatial indexing. However, once you start working with coordinate systems, the architectural differences become much more obvious. These systems include SRIDs, GIS functions, earth-based calculations, and migration scenarios.
Even the terminology differs. MySQL primarily refers to these features as spatial data types, while PostgreSQL distinguishes between built-in geometric types and PostGIS spatial types. These differences affect everything – from indexing and query performance, to data validation and migration complexity.
Traditional relational databases can store latitude and longitude as plain numeric columns, like so:
latitude DECIMAL(10,8)
longitude DECIMAL(11,8)
This approach becomes limiting when applications need to perform functions like finding nearby locations, calculate distances, and determine whether a point falls inside a region. Spacial data types solve these problems by treating location data as first-class objects.
MySQL and PostgreSQL both implement geometry models largely inspired by OGC (Open Geospatial Consortium) standards. Here are some common spatial types used in both systems:
| Spatial Type | Description | Example |
| POINT | Single coordinate location | GPS position |
| LINESTRING | Connected line segments | Roads or routes |
| POLYGON | Closed area | State boundaries |
| MULTIPOINT | Multiple points | Stores locations |
| MULTILINESTRING | Multiple lines | Highway systems |
| MULTIPOLYGON | Multiple polygons | Island groups |
| GEOMETRYCOLLECTION | Mixed geometry objects | Combined map objects |
Spatial support is built directly into MySQL. It implements spatial extensions internally and supports geometry storage, spatial indexes, and spatial functions natively.
A typical spatial column looks like this:
CREATE TABLE stores (
id INT PRIMARY KEY,
location POINT SRID 4326
);MySQL stores geometry data in its own internal binary format consisting of a 4-byte SRID (Spatial Reference System) prefix, followed by standard OGC WKB (Well-Known Binary) data. It fully supports exchanging this data using OGC-compliant formats including WKT (Well-Known Text), standard WKB, and SRIDs.
For example, a location can be represented in WKT as:
POINT(3.3792 6.5244)
This human-readable format is commonly used for inserting or debugging spatial data. You can store it in MySQL using:
INSERT INTO locations (geom)
VALUES (
ST_GeomFromText(
'POINT(3.3792 6.5244)',
4326
)
);In this example, POINT(3.3792 6.5244) is the WKT representation, and 4326 is the SRID. It refers to the widely-used World Geodetic System (WGS), an 84-coordinate system used by GPS and mapping systems. Internally, MySQL converts this into binary geometry data for efficient storage and indexing. The same geometry can also be represented using WKB, the compact binary equivalent of WKT.
Unlike WKT, WKB is not human-readable. Instead, it’s designed for efficient machine processing and data exchange between GIS systems.
MySQL also provides functions for converting between these representations:
SELECT ST_AsText(geom)
FROM locations;
returns:
POINT(3.3792 6.5244)
while:
SELECT ST_AsBinary(geom)
FROM locations;
returns the WKB representation of the geometry.
Leaving out the SRID when creating a spatial object causes MySQL to apply a default value of 0. This specific identifier treats your data as coordinates on a completely flat, infinite Cartesian grid. On this grid, your numbers are just random (X) and (Y) points on an infinite sheet of graph paper. MySQL has no clue if those numbers mean miles, meters, or degrees. It also completely loses track of the fact that the Earth is round!
MySQL 8.0 significantly expanded its spatial capabilities and introduced several new GIS functions that made spatial operations more practical for real-world geographic applications. Earlier MySQL versions already supported core geometry operations, but 8.0 improved standards compliance, SRID awareness, coordinate handling, validation, and geographic calculations.
Importantly, it also added ST_Latitude(), ST_Longitude(), ST_SwapXY() and ST_Transform(). ST_Latitude() and ST_Longitude() were added specifically for geographic coordinate systems and provide a clearer alternative to the older ST_X() and ST_Y() functions. Before MySQL 8.0, developers commonly extracted coordinates using:
SELECT ST_X(location), ST_Y(location)
FROM places;
The problem is that ST_X() and ST_Y() only return the first and second coordinate axes. They do not explicitly indicate whether the values represent longitude or latitude. This often caused confusion in GIS applications, especially when developers accidentally reversed coordinate ordering.
Thankfully, MySQL 8.0 introduced clearer geographic semantics:
SET @pt = ST_GeomFromText(
'POINT(3.3792 6.5244)',
4326
);
SELECT
ST_Longitude(@pt),
ST_Latitude(@pt);These functions work specifically with geographic SRS’ such as SRID 4326 (WGS 84). If the geometry does not use a geographic SRS, MySQL raises an error.
Version 8.0 also added stricter coordinate validation. Longitude values outside (-180, 180], and latitude values outside [-90, 90], now generate errors for geographic coordinates.
For example:
SELECT ST_Latitude(
ST_GeomFromText(
'POINT(3.3792 120)',
4326
)
);…produces a latitude out-of-range error because latitude cannot exceed 90 degrees.
Another major improvement was the addition of ST_Transform() in MySQL 8.0.13, allowing coordinate transformations between SRS’:
SELECT ST_AsText(
ST_Transform(
ST_GeomFromText(
'POINT(3.3792 6.5244)',
4326
),
3857
)
);This converts coordinates from the WGS 84 geographic coordinate system (4326), into the Web Mercator projection (3857) commonly used in web mapping systems.
MySQL 8.0 also introduced newer analytical spatial functions, such as:
| Function | Purpose | MySQL Version |
ST_HausdorffDistance() | Measures similarity between geometries | 8.0.23 |
ST_LineInterpolatePoint() | Finds a point along a line at a percentage distance | 8.0.24 |
ST_LineInterpolatePoints() | Returns multiple interpolated points along a line | 8.0.24 |
ST_Validate() | Returns validated geometry objects | 8.0 |
ST_AsGeoJSON() | Converts geometry into GeoJSON | 8.0 improvements |
For example, ST_AsGeoJSON() became extremely useful for modern web applications because JavaScript mapping libraries, such as Leaflet and Mapbox, commonly use GeoJSON.
SELECT ST_AsGeoJSON(
ST_GeomFromText(
'POINT(3.3792 6.5244)',
4326
)
);Result of the above: {"type":"Point","coordinates":[3.3792,6.5244]}
These additions show how MySQL 8.0 moved beyond basic geometric storage and more toward mature GIS-oriented functionality.
Before discussing PostgreSQL’s advanced spatial capabilities (PostGIS), it’s important to understand that PostgreSQL already includes its own native geometric type system directly within its core engine. These built-in geometric types have existed in PostgreSQL for decades and are completely separate from the PostGIS extension.
This distinction is extremely important – many developers mistakenly assume PostgreSQL’s native geometric types are the same as PostGIS geometry types, but this is not the case.
PostgreSQL geometric types are primarily designed for representing two-dimensional planar objects and performing mathematical geometry operations inside the database. They work well for applications involving shapes, coordinates, computer graphics, engineering calculations, computer-aided design (CAD) style systems, or simpler spatial computations.
However, they are not full GIS types, so don’t provide advanced geographic capabilities such as SRIDs, Earth projections, coordinate transformations, or geospatial standards compliance that PostGIS introduces later.
PostgreSQL provides several native geometry types, which are:
| Types | Description |
| point | A single coordinate point |
| line | Infinite line |
| lseg | Finite line segment |
| box | Rectangular box |
| path | Open or closed connected path |
| polygon | Closed polygon |
| circle | Circle with center point and radius |
These types internally store coordinates using double precision floating-point values.
The point type is the foundation of PostgreSQL’s geometric system. It stores a simple (x,y) coordinate pair:
CREATE TABLE locations (
id SERIAL PRIMARY KEY,
coordinates POINT
);Example insertion:
INSERT INTO locations (coordinates)
VALUES ('(3.3792,6.5244)');You can query it directly:
SELECT coordinates
FROM locations;Result: (3.3792,6.5244)
Unlike PostGIS geometry objects, PostgreSQL’s native point type has no SRID awareness, no coordinate system metadata, no Earth projection support, and no GIS validation rules. It simply represents mathematical coordinates on a flat plane.
The line type represents an infinite line extending endlessly in both directions. PostgreSQL stores it using:
CREATE TABLE routes (
id SERIAL PRIMARY KEY,
route LINE
);And PostgreSQL inserts it using two points:
INSERT INTO routes (route)
VALUES ('((0,0),(5,5))');Infinite lines are rarely used in GIS systems but can be useful in engineering calculations, geometry simulations, and mathematical modeling.
lseg stands for “line segment.” Unlike line, this type stores a finite segment between two endpoints. For example:
CREATE TABLE roads (
id SERIAL PRIMARY KEY,
segment LSEG
);Insert:
INSERT INTO roads (segment)
VALUES ('[(0,0),(10,10)]');This is useful for road fragments, vectors, edges in graph systems, and engineering diagrams.
The box type represents rectangular regions using two opposite corners. For example:
CREATE TABLE regions (
id SERIAL PRIMARY KEY,
area BOX
);Inserting data:
INSERT INTO regions (area)
VALUES ('((0,0),(10,10))');Internally, PostgreSQL automatically normalizes the coordinates to store the upper-right corner and lower-left corner.
The path type represents connected sequences of points. PostgreSQL supports both open paths and closed paths.
Open path example: '[(0,0),(5,5),(10,0)]'
Closed path example: '((0,0),(5,5),(10,0))'
Notice the syntax difference between the two: square brackets [] are used for open path, while parentheses () are used for closed path.
This type is useful for movement tracking, routing simulations, vector graphics, and navigation paths.
polygon represents closed geometric areas. For example:
CREATE TABLE zones (
id SERIAL PRIMARY KEY,
boundary POLYGON
);Inserting data:
INSERT INTO zones (boundary)
VALUES (
'((0,0),(10,0),(10,10),(0,10))'
);Polygons are very similar to closed paths but PostgreSQL treats them differently, providing specialized polygon operators. This type works well for geometric regions, shape analysis, and planar containment tests. However, unlike PostGIS polygons, there’s no SRID support, no spherical geometry, and no coordinate transformation system.
The circle type stores center point and radius. For example:
CREATE TABLE radar (
id SERIAL PRIMARY KEY,
coverage CIRCLE
);Inserting data:
INSERT INTO radar (coverage)
VALUES ('<(5,5),10>');This represents:
center = (5,5)
radius = 10
Circles are useful for radius searches, proximity checks, simulation systems, and geometric computations.
Despite being useful, PostgreSQL geometric types have important limitations. Most significantly, they are fundamentally planar, mathematical, and non-geographic. They do NOT support the following:
For example, point '(3.3792,6.5244)' is simply treated as:
x = 3.3792y = 6.5244
PostgreSQL does not know these represent GPS coordinates (longitude and latitude). This is a major architectural difference compared to PostGIS.
As geospatial applications became more sophisticated, PostgreSQL’s built-in geometric system was no longer sufficient for enterprise GIS workloads. Applications increasingly needed:
This is where PostGIS entered the picture. PostGIS extends PostgreSQL with fully GIS-aware spatial types such as geometry and geography – alongside hundreds of advanced spatial functions, coordinate transformation systems, and enterprise GIS capabilities.
This means PostgreSQL effectively has two different geometry ecosystems: the native geometric types built into PostgreSQL itself, and the advanced GIS-oriented spatial types provided by PostGIS.
In many ways, PostGIS is what elevated PostgreSQL into one of the most widely used spatial databases in the world.
More specifically, PostGIS is an extension that adds spatial object support, spatial indexing, geographic calculations, raster processing, topology features, coordinate transformation systems, and hundreds of GIS functions to PostgreSQL.
Unlike MySQL, where spatial support is built directly into the core database engine, PostgreSQL separates advanced geospatial functionality into an extension architecture.
PostGIS is enabled using CREATE EXTENSION postgis;. Once installed, PostgreSQL gains entirely new spatial data types, operators, indexing strategies, GIS functions, projection systems, and interoperability features. This modular design is one reason PostgreSQL is highly extensible.
The geometry type is the most commonly used PostGIS type. It stores spatial objects on a flat Cartesian coordinate plane. For example:
CREATE TABLE stores (
id SERIAL PRIMARY KEY,
location geometry(Point, 4326)
);This definition contains several important components, such as:
i. Geometry (PostGIS spatial type)
ii. Point (geometry subtype)
iii. 4326 (SRID)
Unlike PostgreSQL native geometric types, PostGIS geometries are SRID-aware. The SRID identifies the coordinate reference system used by the geometry, meaning PostGIS understands that coordinates represent longitude, latitude, and geographic positioning rather than just arbitrary mathematical coordinates.
This distinction changes everything about distance calculations, indexing, coordinate transformations, projections, and GIS interoperability.
One of PostGIS’s most important innovations is the geography type. Compared to geometry, which assumes a flat plane, geography performs calculations on a spheroidal Earth model – important because, of course, Earth is not flat.
For example:
CREATE TABLE airports (
id SERIAL PRIMARY KEY,
location geography(Point, 4326)
);If we want to calculate the distance between Lagos and London, using planar geometry calculations may produce distorted results simply because the Earth curves. The geography type accounts for this with earth curvature, spherical calculations, and geodesic distances. This makes it ideal for GPS systems, airline routing, shipping systems, and global mapping applications.
Here’s an outline of the geometry vs geography tradeoff:
| Feature | Geometry | Geography |
| Calculation model | Flat plane | Spheroidal Earth |
| Performance | Faster | Slower |
| Accuracy for global distances | Lower | Higher |
| Projection support | Extensive | Limited |
| Typical use | Local GIS | Global GIS |
Another reason PostGIS dominates GIS workloads is its enormous function ecosystem. PostGIS provides hundreds of spatial functions. Let’s go over some of the common ones.
| Functions | Purpose |
ST_MakePoint() | Creates point geometry |
ST_GeomFromText() | Creates geometry from WKT |
ST_GeomFromGeoJSON() | Imports GeoJSON |
For example, the ST_MakePoint() function creates a spatial point from the coordinate valuesSELECT ST_MakePoint(3.3792,6.5244);, giving the result POINT(3.3792 6.5244).
In most real-world applications, developers usually assign an SRID immediately after creating the point:
SELECT ST_SetSRID(
ST_MakePoint(3.3792, 6.5244),
4326
);However, that’s not needed here, as ST_MakePoint() creates the geometry while ST_SetSRID() assigns the WGS 84 coordinate system (4326).
| Functions | Purpose |
ST_AsText() | Returns WKT |
ST_AsBinary() | Returns WKB |
ST_AsGeoJSON() | Returns GeoJSON |
An example using the ST_AsGeoJSON() function:
SELECT ST_AsGeoJSON(
ST_SetSRID(
ST_MakePoint(3.3792, 6.5244),
4326
)
);The ST_AsGeoJSON() function converts spatial data into GeoJSON format, which is commonly used by mapping libraries such as Leaflet, OpenLayers, and Mapbox.
Result:
{
"type": "Point",
"coordinates": [3.3792, 6.5244] }This makes PostGIS highly suitable for APIs and frontend GIS applications.
Another powerful feature of PostGIS is spatial relationship analysis, summarized as so:
| Function | Purpose |
ST_Contains() | Checks containment |
ST_Intersects() | Detects overlaps |
ST_Touches() | Detects touching geometries |
ST_Within() | Checks inclusion |
The ST_Contains() function checks whether one geometry completely contains another. For example:
SELECT ST_Contains(
ST_GeomFromText(
'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))',
4326
),
ST_GeomFromText(
'POINT(5 5)',
4326
)
);This query checks whether the polygon contains the point (5,5). Functions like ST_Contains() are widely used for geofencing, delivery zones, and more.
One of the most heavily used PostGIS capabilities is spatial distance calculation. The functions include:
| Function | Purpose |
ST_Distance() | Calculates distance |
ST_Length() | Calculates line length |
ST_Area() | Calculates polygon area |
ST_Perimeter() | Calculates perimeter |
The ST_Distance() function calculates the distance between two geometries. For example:
SELECT ST_Distance(
ST_SetSRID(
ST_MakePoint(3.3792, 6.5244),
4326
)::geography,
ST_SetSRID(
ST_MakePoint(3.4219, 6.4433),
4326
)::geography
);In this query, both points are converted to the geography type, and PostGIS performs Earth-aware distance calculations. This functionality is commonly used in ride-sharing applications, delivery systems, nearby searches, etc.
Beyond basic geometry operations, PostGIS also provides several advanced GIS capabilities that distinguish it from simpler spatial database systems. These include:
These capabilities are one reason PostGIS is commonly used in enterprise GIS systems, scientific research, mapping infrastructure, environmental monitoring, and large-scale geospatial analytics.
A major migration takeaway is that PostgreSQL’s native geometric types are not equivalent to MySQL spatial types. For most GIS-oriented migrations, PostGIS is usually the proper migration target – not PostgreSQL’s built-in geometric system.
Another important difference is SRID handling. PostGIS enforces much stricter coordinate systems and geometry validation than in MySQL which, as a result, often exposes hidden issues such as invalid geometries, inconsistent SRIDs, or improperly formatted spatial data during migration.
Teams migrating from MySQL also need to understand the distinction between PostGIS geometry and geography types. Choosing the wrong type can affect distance calculations, indexing behavior, accuracy, and query performance.
Finally, while PostGIS still offers a much larger spatial ecosystem, MySQL 8.0 greatly improved developer experience for applications involving GPS coordinates, mapping systems, routing, geofencing, and location-aware services.
MySQL spatial types are GIS-aware: they support SRIDs, coordinate systems, and geographic calculations. PostgreSQL’s native geometric types (point, polygon, circle, etc.) are purely mathematical — they work on a flat plane with no coordinate system awareness. For GIS work in PostgreSQL, you need the PostGIS extension, not the built-in types.
PostGIS is a PostgreSQL extension that adds full GIS capabilities: SRID-aware geometry, a geography type for spherical Earth calculations, coordinate transformation, raster support, topology, and hundreds of spatial functions. It exists because PostgreSQL’s built-in geometric types weren’t sufficient for real-world geospatial workloads.
Use geometry for local or planar calculations where performance matters most. Use geography when working with global coordinates (like GPS data) where Earth’s curvature affects accuracy — for example, calculating flight distances or shipping routes across continents.
MySQL 8.0 added stricter SRID enforcement, new geographic functions like ST_Latitude() and ST_Longitude(), coordinate validation (rejecting out-of-range values), ST_Transform() for projection conversion, and improvements to ST_AsGeoJSON() for compatibility with mapping libraries like Leaflet and Mapbox.
Three main issues: PostgreSQL’s native geometric types are not equivalent to MySQL spatial types — PostGIS is the correct migration target. PostGIS enforces stricter geometry validation and SRID consistency, which often surfaces hidden data quality problems. And choosing between PostGIS geometry and geography incorrectly can affect distance accuracy, query performance, and indexing behavior.
The post MySQL vs PostgreSQL: spatial data types, functions, and migration pitfalls explained appeared first on Simple Talk.
When a FHIR deployment goes wrong, the failure usually traces back to something decided, or not decided, before any software was installed.
Security wasn’t brought in until the design was already done. Nobody asked how many requests production would actually see. Nobody asked whether the FHIR server would be the source of truth or just a synced copy, and that single question ends up shaping half the architecture.
This is essentially the conversation we have with every customer before anything gets built, generalized enough that any team can run it themselves.
It has less to do with technology than you’d think. The most important thing is getting the right people in the room early and asking a short list of questions whose answers determine everything else.
Who you get in the room matters more than which reference architecture you pick.
In practice that looks like:
Some organizations cover all of these roles with two people. Others need a full team per function. The roles matter, not the headcount.
A handful of questions, asked honestly, do most of the planning work.
Which implementation guides do you need to support? That decides your conformance resources: custom search parameters, profiles, code systems, value sets, and for quality use cases, measures and libraries.
How many requests will production actually see? The honest range runs from a few requests a month for a compliance-only deployment to thousands of requests per second when the FHIR server is the central interoperability layer for seven or eight applications. Those are different architectures. It’s also important to plan for potential growth in use over the next few years. If it’s possible that use could grow quickly, plan a scalable platform from the beginning.
How much data? Thousands of resources sit fine in a simple database and basic FHIR server, but millions/billions change your storage, indexing, and loading strategy.
Is the API public or secured? Public endpoints change your threat model completely. Public APIs are where it gets scary, because anyone who knows the endpoint can hit it. In practice, it’s often the provider directory, the least sensitive data you host, that draws the most traffic, including the app that re-downloads everything every 30 seconds. That’s what rate limiting with a proxy service is for.
Do you need validation in production? Validation is expensive to run in the request pipeline. If outside parties write to your server, you likely need it there, along with a plan for handling failures: either reject invalid data strictly or admit it while flagging it for review. Either way, you need somewhere for failed messages to land, since not everyone using your API knows how to interpret an OperationOutcome.
If only your own internal pipeline writes to the server, validate earlier in that pipeline instead, before data reaches the server. One advantage: validation scales out well. Since it barely touches the database layer, you can place multiple validating servers/services in front of your main server to handle the load.
One question decides your backup strategy, your availability requirements, and a chunk of your cost: Is the FHIR server the system of record, or a synchronized copy?
If it’s the source of truth, back it up like the transactional system it is. If it’s not, backing up billions of resources is an expensive way to protect data that already lives somewhere else. You might be better off reloading from source using your staging area and a last-updated window. Knowing which one you’re dealing with changes how much high-availability you buy and how much disaster recovery you build into the system.
The same logic applies to deployment. Cloud gives you scaling, geographic redundancy, and low upfront cost, and it’s the default preference for me. But regulation and data residency can override that, and costs are hard to predict until it’s running. On-premises trades capital cost and dedicated system engineers for control. A hybrid setup, data on-premises with compute in the cloud over a secure pipe, is often the workable middle ground.
Portability matters too. Whatever you choose, you want the option to move it later without a rebuild, since regulation, cost, or a platform migration can force that decision for you.
Almost every FHIR server sits behind a proxy service to direct traffic, reroute during upgrades, and rate-limit clients that misbehave. Behind that, SMART on FHIR, built on OAuth2, is the standard for authorizing clients, with your identity provider (Microsoft Entra ID, Okta, Keycloak, AWS Cognito) federated via OpenID Connect or SAML.
Here’s the catch: off-the-shelf identity providers aren’t SMART-aware. Entra ID, for example, wants to issue roles, not scopes, and has no idea which patient resource a logged-in user maps to. Something must own that mapping and inject the right scopes and claims into tokens, which is why we built Firely Auth to sit between the identity provider and the server, rather than asking a general-purpose product to speak FHIR.
We learned one lesson the hard way, too: audit belongs elsewhere. We once had a server that had become 98% audit events and hardly any actual data. Audit trails belong in Splunk, Elasticsearch, or your observability platform, not stored as resources next to the clinical data.
Get the questions answered honestly, and the architecture decisions mostly make themselves.
Serving multiple separate client organizations off one deployment points toward multi-tenancy. A single organization with clean isolation needs is better served as single-tenant.
A legacy system you can’t migrate but still need to expose in real time calls for a facade in front of it. Otherwise, a native FHIR repository is the better fit.
And if multiple FHIR versions or US Core versions are in play, that usually means separate servers per version, with the proxy routing requests to the right one by profile, since resources don’t map one to one across versions.
None of these are exotic. All of it goes faster and cheaper when the right people answer the right questions before the first server gets provisioned. Plan the room first. The server is the easy part.
Whether you’re just starting to think this through, or already in the middle of it and want another perspective, get in touch. We’re always happy to talk it through.
The post How to plan a FHIR server deployment: stakeholders, questions, and architecture appeared first on Firely.
Scott and Wes tackle your questions on the rise of the design engineer, why AI still lacks “taste” (and why it’s about more than just looks), and how to actually write tests in the age of AI-assisted coding. Plus: is AI a bubble about to burst, keeping coding agents efficient in massive codebases, introducing kids to AI, a Linux life update, and more!
Syntax: X Instagram Tiktok LinkedIn Threads
Wes: X Instagram Tiktok LinkedIn Threads
Scott: X Instagram Tiktok LinkedIn Threads
Randy: X Instagram YouTube Threads
Lately I've had the opportunity to travel by train and coach, during which time I also tend to work. It's really only during these periods that I'm reminded of how web sites fail so terribly over a slow connection.
On the odd occasion I can be guilty of this too. I had a tiny tool that takes markdown and renders it for quick reading (no apps, or split view in VS Code, etc). When I loaded it up on the train, the page asked me to drop the file in to be rendered, which I dutifully did, only for the page to load the source markdown.
It's nothing new, but Progressive Enhancement doesn't only apply to HTML being enhanced with JavaScript. It also applies within JavaScript. Sometimes this was the cut the mustard test, but sometimes it's about thinking laterally about JavaScript. In particular, can I capture the user's intent if they try to interact with my page before it's fully ready?
Below I've made a visual demonstration of the issue, and the effect after I fixed the logic. It shows the browser throttled to "good 2G" network connectivity, and first I try to drop the markdown file and the browser (naturally) assumes I want to open the file. The result being the browser navigates away from the page to render the raw markdown - not what I wanted.
The second part of the video shows with the same throttled connection, I can drop the file, and the page remains in place with a "Loading" indicator. The browser status shows that more files are being loaded (over the network from esm.sh) and when those settle down after 10 seconds, the fully rendered page loads. It's slow, but it got there in the end.
The original source code had the JavaScript at the end of the HTML but one of the first tasks was to import the markdown parsing module from esm.sh. This is a significant amount of code. Then it imports highlightjs (which might not even be required). Although this was very much a quickly thrown together project, it does pull 600kB (compressed) - which feels rather heavy and I'd like to optimise if this wasn't just for me.
That 600kB, decompressed to 1.3MB, has to be downloaded and parsed before the browser parses the "author code", i.e. my code, that does the rendering of the markdown file.
By prioritising the user interaction and including only the required JavaScript both inline and directly after the source HTML that's going to encourage the user to interact, I'm able to catch the interaction and queue up the work until the prerequisite functionality is loaded.
That means breaking out the event handler binding, queue logic and simple visual feedback from the main body of JavaScript.
The result is that, even over a GPRS connection, the full interactivity still works, even if it takes nearly 2 minutes to complete.
This particular project is designed not to have a backend at all (that's just a constraint I set myself). Though I can see how this could actually upload the markdown to a server for rendering. I imagine I can use Netlify ODB - though I haven't measured the timings, I'd bet that it's still faster than 2 minutes over GPRS.
This is not a new method by any measure at all. I was only reminded of it because I was on a train. Admittedly my daily client work is deep in backend API work, so I don't often get to take a closer look at front end JavaScript so much these days!
Originally published on Remy Sharp's b:log