# gff3sort fixes the tie that GNU sort gets wrong before tabix sees your file

> gff3sort is a Perl script that sorts a GFF3 file for tabix indexing and then repairs the ordering of features that share a start position, moving Parent= lines behind their children. Three flags adjust the behaviour, and the cheapest one to get wrong is the chromosome order.

**tao-bioinfo/gff3sort** — GFF3sort: A Perl Script to sort gff3 files and produce suitable results for tabix tools

- Repository: https://github.com/tao-bioinfo/gff3sort
- Stars: 50 · Forks: 20
- Language: Perl
- License: GPL-3.0
- Published: 2026-08-17 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/tao-bioinfo-gff3sort

## tabix wants columns 1 and 4 sorted, and neither sorter gets ties right

The reason this script exists is a two-line requirement. tabix, from htslib, needs its input sorted by chromosome and by position, and for GFF3 that means column 1 and column 4. Both of the obvious ways to do it are one command:

```bash
sort -k1,1 -k4,4n myfile.gff > myfile.sorted.gff
```

The alternative uses the GenomeTools `gt` command, `gt gff3 -sortlines -tidy -retainids`, and the README treats the two as interchangeable. Once sorted, the file is compressed and indexed:

```bash
bgzip myfile.sorted.gff
tabix -p gff myfile.sorted.gff.gz
```

The bug is in the ties. When two lines share a chromosome and a start position, both GNU sort and `gt` place them in an arbitrary order, and an arbitrary order can put a parent feature after its own children. Two mRNA lines starting at position 473 can land behind exon lines that also start at 473.

That is not cosmetic. Consumers that expect a parent before its exons break, and the README names a JBrowse issue as the symptom to look for.

## The repair is one rule: Parent= lines move behind lines without Parent=

What the script adds after sorting is narrow and mechanical. For lines sharing a start position, it moves the ones carrying a `Parent=` attribute behind the ones that do not, matching the attribute name case-insensitively.

That single rule is the whole point. A feature line with `Parent=` is a child by definition, so putting children first inverts the relationship a viewer relies on. Lines without a `Parent=` attribute, which is where parent features live, come out ahead of them.

The README shows the before and after on the same two-transcript example, where both mRNA lines start at 473 and both are followed by exons at the same coordinate. Sorted naively, the exons come first. Sorted by the script, the two mRNA lines come first and the exons follow.

Because the rule only touches ties, it does not disturb the ordering tabix actually depends on. Chromosome and start position remain sorted; only the internal order of equal keys is corrected.

## --precise costs two to three times the time and only fixes broken input

There is one flag for people whose input is already wrong.

```bash
gff3sort.pl [input GFF3 file] >output.sort.gff3
```

That is the whole invocation: a filename in, a sorted file on standard output, which is then redirected. Nothing is written in place and there is no output path argument.

The first optional flag is `--precise`, and the README's description of it is unusually precise about when to reach for it. Precise mode runs about two to three times slower than the default, and it is only needed if the original GFF3 files have parent features appearing behind their children features.

That condition is worth pausing on, because it describes an input that has already been misordered upstream. If your annotation came from an assembler or a converter that emitted children before parents, the default mode will sort correctly from there on. The precise mode exists to deal with the case where the disorder is deeper than a simple sort can fix, and paying a two to three times cost on every file for a condition you do not have is the wrong trade.

## --chr_order defaults to alphabet, which is not what most genomes want

The second flag controls how chromosome identifiers are ordered, and the default is the first thing to check.

```bash
--chr_order         Select how the chromosome IDs should be sorted.
                    Acceptable values are: alphabet, natural, original
                    [Default: alphabet]
```

Three values are accepted. `alphabet` is the default. `natural` is the ordering that treats embedded numbers as numbers, so chromosome 2 comes before chromosome 10 instead of after it. `original` keeps the order the identifiers arrived in.

This matters because GFF3 files from different sources disagree about chromosome naming, and the alphabetical default will sort numeric names as text. A file with chromosome identifiers `1`, `2`, `10` sorted alphabetically puts `1`, `10`, `2`, which tabix will index faithfully and every browser will then display in that order.

`original` is the option to reach for when the file already has a meaningful order that the other two would destroy, such as an assembly's contig order or a naming scheme that encodes biology rather than numbers.

## The --extract_FASTA description stops mid-sentence

The third flag is the one the documentation does not finish.

```bash
--extract_FASTA     If the input GFF3 file contains FASTA sequence
```

That is the whole entry. It names the condition, a GFF3 file containing FASTA sequence, and then ends without saying what the script does about it, whether that is extraction, rewriting, or stripping.

Worth knowing because GFF3 does permit a `##FASTA` section at the end of the file, and the script has to decide what to do with it when it reorders lines above it. A user who has such a section has to determine the behaviour by experiment, or by reading the Perl, since the README will not settle it.

It is a small gap in an otherwise unusually specific set of flag descriptions. The `--precise` and `--chr_order` entries both state the cost, the trigger condition and the accepted values, which makes the truncated third entry read like an unfinished edit rather than a deliberate omission.

## One release in 2020, a 2017 paper, and a sibling script for checking disorder

The repository holds four things at the top level: `gff3sort.pl` itself, `check-disorder.pl`, a `Sort/` directory and the README and LICENSE. The second Perl script is not documented in the README at all, but its name says what it is for, checking whether a file is disordered in the first place, which is the question you would ask before deciding whether `--precise` is needed.

Licensing is GPL-3.0, which matters for a script you may want to fold into an annotation pipeline rather than call.

On cadence, the last push to the repository landed on 2020-06-27, and release v1.0.0 was published the same day. Before that there is a single earlier tag, v0.1-alpha from 2017-06-28. So the project has one substantive release, made in the year the underlying problem was still being reported in genome browsers.

The method itself was published: Zhu T, Liang C, Meng Z, Guo S and Zhang R, GFF3sort: A novel tool to sort GFF3 files for tabix indexing, BMC Bioinformatics 2017, volume 18, article 482. If you adopt the script on a large annotation set, that paper is the place to check what was validated and what was not.

## Conclusion

gff3sort fits a genome browser or annotation viewer that refuses to load a tabix-indexed GFF3 whose parent features sit after their exons, which is the failure mode JBrowse users ran into. It does not fit a general annotation pipeline, because it sorts and reorders lines and does nothing else. Before running it on a real annotation set, check your chromosome names against --chr_order, since the default is alphabetical rather than natural, and note that the last push to the repository was on 2020-06-27.

## FAQ

### What does gff3sort do to a GFF3 file?

It sorts the file by chromosome and start position the way tabix requires, then repairs features that share a start position by moving lines carrying a Parent= attribute behind lines without one. Without that repair, a parent feature can be placed after its own children.

### When do I need the --precise flag in gff3sort?

Only when the original GFF3 file already has parent features appearing behind their children features. The README states that precise mode runs about two to three times slower than the default mode.

### Which chromosome sort orders does gff3sort support?

Three values for --chr_order: alphabet, natural and original. The default is alphabet, so a file whose chromosome identifiers are numbers is otherwise ordered as text rather than as numbers.

### How do I index a sorted GFF3 file with tabix?

Run gff3sort.pl to produce the sorted file, then bgzip it and index it with tabix -p gff. The README also shows GNU sort -k1,1 -k4,4n and gt gff3 -sortlines as manual alternatives, both of which share the tie-ordering problem this script exists to avoid.

### What license is gff3sort under, and when was it last updated?

GPL-3.0. The last push to the repository landed on 2020-06-27, the same day as release v1.0.0, and the earlier tag v0.1-alpha dates from 2017-06-28.

## Sources

- [Official README](https://github.com/tao-bioinfo/gff3sort#readme)
- [Project repository](https://github.com/tao-bioinfo/gff3sort)
- [Release notes](https://github.com/tao-bioinfo/gff3sort/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tao-bioinfo-gff3sort
