Jinja FAQ: What's the deal with '~'?

~ is the string concatenation operator. It coerces both sides to strings, then concatenates them.

Follow-up question: “Doesn’t + concatenate strings? Why not just use that?”

+ is the addition operator, which is overloaded to mean concatenation when both sides of the expression are strings. While they’re often interchangeable, developing a habit of using the concatenation operator means that you don’t have to worry about or code around the situations where they’re not.

- hosts: localhost
  tasks:
    - debug:
        var: 13 + 37
    - debug:
        var: 13 ~ 37
    - debug:
        var: 13 ~ '37'
    - debug:
        var: 13 | string + '37'
    - debug:
        var: 13 + '37'
TASK [Addition isn't concatenation] ********************************************
ok: [localhost] => {
    "13 + 37": "50"
}

TASK [Concatenation is concatenation] ******************************************
ok: [localhost] => {
    "13 ~ 37": "1337"
}

TASK [Concatenation handles mixed types] ***************************************
ok: [localhost] => {
    "13 ~ '37'": "1337"
}

TASK [It's possible to do the coercion manually, but who wants to do that?] ****
ok: [localhost] => {
    "13 | string + '37'": "1337"
}

TASK [Addition doesn't like mixed types] ***************************************
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{13 + '37'}}): unsupported operand type(s) for +: 'int' and 'str'"}