Short answer
To turn a CSV into a GIS layer you need three things: which column is X (longitude or easting) and which is Y (latitude or northing), the CRS those numbers are in, and a real spatial output format (GeoPackage, not another CSV). Get the column order and CRS right and the rest is one command. Get either wrong and your points land in the ocean, in the wrong hemisphere, or scaled into a tiny cluster near (0,0).
The single most common error is axis order: a file labelled lat, lon lists Y before X, the reverse of the X,Y convention most tools expect. Map the columns deliberately, every time.
Read the file before you map anything
Open the raw CSV and answer four questions:
- Which columns hold coordinates, and in what order? Headers like
lon/lat,x/y,easting/northing,POINT_X/POINT_Y. If you seelatfirst, remember it is Y. - What is the magnitude? Values between −180 and +180 with decimals are decimal degrees (geographic). Values in the hundreds of thousands to millions are metres in a projected grid. A column that runs 0-90 paired with one running 0-180 is degrees.
- Is it decimal degrees or DMS?
48.8566is decimal.48°51'24"Nor48 51 24 Nis degrees-minutes-seconds and must be converted first. - What delimiter and encoding? Comma vs semicolon (common in European locales where comma is the decimal separator), and UTF-8 vs Latin-1 for any accented attribute text. Encoding mistakes corrupt names, not geometry — but they still ruin a deliverable.
Decide the CRS from the magnitudes and any metadata the source gave you. Decimal degrees are almost always WGS84, EPSG:4326. Metre coordinates need their specific grid, e.g. EPSG:32631 (UTM 31N) or EPSG:27700 (British National Grid). Assigning a CRS does not move the points to the right place; it only declares what frame the existing numbers belong to, so it must be the truth.
Method 1: QGIS (Add Delimited Text Layer)
The interactive path. Layer → Add Layer → Add Delimited Text Layer. Set:
- Geometry definition: Point coordinates.
- X field → the longitude/easting column; Y field → the latitude/northing column. (This is where you correct lat-first files.)
- Geometry CRS → the CRS the numbers are in (e.g. EPSG:4326).
- Encoding → UTF-8 unless you know otherwise.
The layer loads as a virtual view over the CSV. It is not yet a real dataset — right-click → Export → Save Features As → GeoPackage to materialise it. If your analysis needs metres, set the export CRS to a projected grid here.
Method 2: GDAL/OGR (scriptable, reproducible)
For pipelines, ogr2ogr with open options reads coordinate columns directly:
ogr2ogr -f GPKG points.gpkg sites.csv \
-oo X_POSSIBLE_NAMES=lon,longitude,x,easting \
-oo Y_POSSIBLE_NAMES=lat,latitude,y,northing \
-a_srs EPSG:4326 -nln sites
-a_srs assigns the source CRS (use the CRS the numbers are in). To also reproject to a metric grid in one step, add -t_srs:
ogr2ogr -f GPKG points_utm.gpkg sites.csv \
-oo X_POSSIBLE_NAMES=lon -oo Y_POSSIBLE_NAMES=lat \
-a_srs EPSG:4326 -t_srs EPSG:32631 -nln sites
For full control over field types and quoting, write a small .vrt with <OGRVRTLayer> and <GeometryField encoding="PointFromColumns" x="lon" y="lat"/>, then point ogr2ogr at the VRT. The VRT also lets you cast columns (e.g. force an ID to text so leading zeros survive).
Method 3: PostGIS
If the data belongs in a database, load the CSV into a staging table and build geometry explicitly:
ALTER TABLE staging ADD COLUMN geom geometry(Point, 4326);
UPDATE staging
SET geom = ST_SetSRID(ST_MakePoint(lon::float8, lat::float8), 4326);
CREATE INDEX ON staging USING GIST (geom);
Note ST_MakePoint(lon, lat) — X first. ST_SetSRID tags the geometry with the CRS; it does not transform. To get a metric working copy, ST_Transform(geom, 32631).
Worked example: a DMS field-notebook export
A CSV reads station, lat_dms, lon_dms with values like 48°51'24.0"N, 2°17'40.0"E. Geometry tools cannot read DMS, so convert first. The formula is decimal = deg + min/60 + sec/3600, negated for S and W. In a QGIS field calculator or a spreadsheet, parse the components and apply the sign, producing lat, lon decimal columns. Then import as EPSG:4326 using any method above. Skipping the conversion and feeding 48°51'24"N to the X/Y mapper yields nulls or zeros, the classic "all my points are at (0,0)" symptom.
Common pitfalls and why they happen
- Swapped X/Y. A
lat, lonfile mapped as X,Y puts points in the wrong hemisphere because longitude and latitude got transposed. Always confirm which column is which. - Wrong CRS assigned. Calling projected metres "EPSG:4326" scales the world into a speck near (0,0); calling degrees a UTM grid throws points far offshore. Assign the CRS the numbers truly use.
- Leading zeros and IDs lost. A code like
007read as a number becomes7. Cast such columns to text via a VRT or staging schema. - Decimal comma locale. European CSVs may use
48,8566; a parser expecting.reads garbage. Set the locale or pre-clean. - Encoding mangles names. Non-UTF-8 source text corrupts accents on import. Declare the encoding explicitly.
- Treating the CSV layer as saved. A QGIS delimited-text layer is a live view; if the CSV moves, the layer breaks. Export to GeoPackage.
QA and validation
Load the new layer on a basemap and confirm the points fall where they should — a quick visual check catches axis and CRS errors instantly. Verify the feature count matches the CSV row count (minus any rows with blank coordinates). Open the attribute table to confirm IDs, accents, and field types survived. If you reprojected, measure one known distance in the metric copy as a final sanity check, and keep the original CSV alongside the GeoPackage so the import is reproducible.
Bathyl perspective
We treat CSV import as a small but auditable conversion: confirm axis order and the true CRS, build geometry explicitly, and export to a real format with the original kept beside it. A coordinate file is only "in GIS" once another analyst can open it, see the points in the right place, and reproduce how they got there.
Related reading
- CRS for Field GPS Data
- Why Shapefile Encoding Breaks Accents
- Why Your GIS Layers Do Not Line Up
- Spatial data products